vc简易网络服务器、客户端实现
生活随笔
收集整理的這篇文章主要介紹了
vc简易网络服务器、客户端实现
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
一、服務器部分代碼
頭文件:server.h#include <winsock2.h> #include <stdio.h> #include <windef.h>
#ifndef TCP_SERVER_H #define TCP_SERVER_H
#pragma warning(disable : 4996)
#define MAX_CLIENT (100) #define LISTEN_PORT (60000) #define CLIENT_TIMEOUT (15 * 60 * 60) /*客戶端中斷15分鐘則服務器自動掉線*/ #define MAX_TCP_PACKET_SIZE (1492)/*tcp最大數(shù)據(jù)包字節(jié)數(shù)*/
typedef struct __client_item { ????SOCKET client; ????sockaddr_in form; ????unsigned int id; ????DWORD dwThreadId; ????HANDLE hThread; }_client_item;
typedef struct __client_list { ????DWORD client_cnt; ????_client_item client_item[MAX_CLIENT]; }_client_list;
DWORD WINAPI serve_client_thread_func( LPVOID param_ptr );
#endif/*TCP_SERVER_H*/ 源文件:server.cpp#include "server.h" #include <sys\stat.h> #include <time.h>
_client_list client_list;
CRITICAL_SECTION cs_serve_main; CRITICAL_SECTION cs_serve_thread;
_client_list *get_client_list(void) { ????return &client_list; }
void client_list_cnt_inc(void) { ????_client_list *client_list_ptr = get_client_list(); ???? ????client_list_ptr->client_cnt++; }
void client_list_cnt_dec(void) { ????_client_list *client_list_ptr = get_client_list();
????client_list_ptr->client_cnt--; }
unsigned int get_free_client_index(void) { ????int i = 0; ????unsigned int id = 0; ????_client_list *client_list_ptr = get_client_list();
????for(i = 0; i < MAX_CLIENT; i++) ????{ ????????id = client_list_ptr->client_item[i].id; ????????if( UINT_MAX == id ) ????????{ ????????????break; ????????} ????}
????return i; }
_client_item *get_client_item(unsigned int index) { ????_client_list *client_list_ptr = get_client_list();
????if( index >= MAX_CLIENT ) ????{ ????????return NULL; ????}
????return &client_list_ptr->client_item[index]; }
void set_client_item(unsigned int index, _client_item *client_item_ptr) { ????_client_list *client_list_ptr = get_client_list(); ???? ????if( index >= MAX_CLIENT ) ????{ ????????return; ????}
????client_list_ptr->client_item[index] = *client_item_ptr; }
SOCKET g_sk_server;
int main() { ????SOCKET server; ????WSADATA wsaData; ????sockaddr_in local; ????int nRet = 0; ????int sockaddr_in_sizeof = 0; ????unsigned int index = 0; ????_client_item *client_item_ptr = NULL; ????_client_item client_item = {0}; ????_client_list *client_list_ptr = NULL; ????SOCKET client; ????sockaddr_in from; ????DWORD dwThreadId; ????HANDLE hThread;
????nRet = WSAStartup(0x101, &wsaData);
????if( 0 != nRet ) ????{ ????????return 0; ????} ????
????// 現(xiàn)在我們來為sockaddr_in結(jié)構(gòu)賦值。 ????local.sin_family = AF_INET; // 地址族 ????local.sin_addr.s_addr = INADDR_ANY; // 網(wǎng)際IP地址 ????local.sin_port = htons(LISTEN_PORT); // 使用的端口
????// 由socket函數(shù)創(chuàng)建我們的SOCKET。 ????server = socket(AF_INET, SOCK_STREAM, 0); ????//server = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,NULL, 0, WSA_FLAG_OVERLAPPED);
????// 如果socket()函數(shù)失敗,我們就退出。 ????if( server == INVALID_SOCKET ) ????{ ????????return 0; ????}
????// bind將我們剛創(chuàng)建的套接字和sockaddr_in結(jié)構(gòu)聯(lián)系起來。 ????// 它主要使用本地地址及一個特定的端口來連接套接字。 ????// 如果它返回非零值,就表示出現(xiàn)錯誤。 ????nRet = bind(server, (sockaddr*)&local, sizeof(local)); ????if( 0 != nRet ) ????{ ????????return 0; ????}
????// listen命令套接字監(jiān)聽來自客戶端的連接。 ????// 第二個參數(shù)是最大連接數(shù)。 ????nRet = listen(server, MAX_CLIENT); ????if( 0 != nRet ) ????{ ????????return 0; ????}
????g_sk_server = server;
????// 我們需要一些變量來保存客戶端的套接字,因此我們在此聲明之。 ????InitializeCriticalSection(&cs_serve_main);/*初始化臨界區(qū)*/ ????InitializeCriticalSection(&cs_serve_thread);/*初始化臨界區(qū)*/ ????client_list_ptr = get_client_list(); ????memset(client_list_ptr, 0xff, sizeof(_client_list)); ????memset(&client, 0, sizeof(SOCKET)); ????memset(&from, 0, sizeof(sockaddr_in));
????sockaddr_in_sizeof = sizeof(sockaddr_in);
????while( TRUE ) ????{ ????????index = get_free_client_index();
????????if( index >= MAX_CLIENT ) ????????{/*已經(jīng)達到最大連接數(shù)*/ ????????????continue; ????????}
????????client_item_ptr = get_client_item(index);
????????client_item_ptr->client = accept(server, ????????????(struct sockaddr*)&client_item_ptr->form, &sockaddr_in_sizeof);
????????if( INVALID_SOCKET == client_item_ptr->client ) ????????{/*連接錯誤*/ ????????????Sleep(500); ????????????continue; ????????}else ????????{ ????????????printf("Connection from %s\n", inet_ntoa(client_item_ptr->form.sin_addr) ); ????????}
????????/* 多線程開始*/ ????????EnterCriticalSection(&cs_serve_main);/*進入臨界區(qū)*/ ????????hThread = CreateThread( ????????????NULL, // no security attributes ????????????0, // use default stack size ????????????serve_client_thread_func, // thread function ????????????client_item_ptr, // argument to thread function ????????????CREATE_SUSPENDED, // use default creation flags ????????????&dwThreadId); // returns the thread identifier
????????if( NULL != hThread ) ????????{ ????????????client_item_ptr->hThread = hThread; ????????????client_item_ptr->dwThreadId = dwThreadId; ????????????client_item_ptr->id = index; ????????} ????????client_list_cnt_inc();
????????LeaveCriticalSection(&cs_serve_main);/*離開臨界區(qū)*/
????????if( NULL != client_item_ptr->hThread ) ????????{ ????????????ResumeThread(client_item_ptr->hThread); ????????}
????????client_item_ptr = NULL; ????????/*end 多線程開始*/ ????}
????//關(guān)閉套接字,并釋放套接字描述符。 ????closesocket(server); ????WSACleanup();
????DeleteCriticalSection(&cs_serve_thread);/*刪除臨界區(qū)*/ ????DeleteCriticalSection(&cs_serve_main);/*刪除臨界區(qū)*/
????return 0; }
void serve_client_thread_clear(SOCKET sock_client, ???????????????????????????????sockaddr_in *sockaddr_client_ptr, ???????????????????????????????UINT32 client_id, ???????????????????????????????char *msg, ???????????????????????????????_client_item *client_item_ptr ???????????????????????????????) { ????int msg_len = strlen(msg);
????if( msg_len > 0 ) ????{ ????????send(sock_client, msg, msg_len + 1, 0); ????}
????closesocket(sock_client);/*關(guān)閉連接*/
????client_list_cnt_dec(); ???? ????memset(client_item_ptr, 0, sizeof(_client_item)); ????set_client_item(client_id, client_item_ptr); }
DWORD WINAPI serve_client_thread_func(LPVOID param_ptr) { ????char buf[MAX_TCP_PACKET_SIZE]; ????_client_item *client_item_ptr = (_client_item *)param_ptr; ????SOCKET sock_client = 0; ????sockaddr_in sockaddr_client = {0}; ????unsigned int client_id = 0; ????_client_list *client_list_ptr = get_client_list(); ????int recv_size = 0; ????time_t sock_free_cur_time = 0; ????time_t sock_free_kill_time = 0; ???? ????int n_ret = 0; ????fd_set fdread; ????timeval tv;
????while( NULL == client_item_ptr->hThread );
????sock_client = client_item_ptr->client; ????sockaddr_client = client_item_ptr->form; ????client_id = client_item_ptr->id;
????sprintf(buf, "%s:%d you id=%d\n", inet_ntoa(sockaddr_client.sin_addr), ????????sockaddr_client.sin_port, client_id);
????send(sock_client, buf, strlen(buf) + 1, 0);
????do ????{ ????????/*這部分代碼在此處必須每次都執(zhí)行*/ ????????FD_ZERO(&fdread);//初始化fd_set ????????FD_SET(sock_client, &fdread);//分配套接字句柄到相應的fd_set ????????tv.tv_sec = 1;//這里我們打算讓select等待1s后返回,避免被鎖死,也避免馬上返回 ????????tv.tv_usec = 0; ????????/*end 這部分代碼在此處必須每次都執(zhí)行*/
????????select(0, &fdread, NULL, NULL, &tv); ????????n_ret = FD_ISSET(sock_client, &fdread); ????????if( 0 == n_ret )/*沒有數(shù)據(jù)*/ ????????{ ????????????continue; ????????}
????????recv_size = recv(sock_client, buf, sizeof(buf), 0); ????????if( recv_size <= 0) ????????{/*socket 錯誤,斷開連接并退出*/ ????????????/*超時,線程退出*/ ????????????printf("client time out ip=%s:port=%d:id=%d\n", ????????????????inet_ntoa(sockaddr_client.sin_addr), sockaddr_client.sin_port, client_id);
????????????EnterCriticalSection(&cs_serve_thread);/*進入臨界區(qū)*/
????????????memset(buf, 0, sizeof(buf)); ????????????serve_client_thread_clear(sock_client, &sockaddr_client, client_id, buf, client_item_ptr);
????????????LeaveCriticalSection(&cs_serve_thread);/*離開臨界區(qū)*/
????????????ExitThread(0);/*退出線程*/ ????????} ????????sock_free_cur_time = 0;
????????if( ('q' == buf[0]) && (0 == buf[1]) ) ????????{/*客戶端主動退出*/ ????????????sprintf(buf, "client exit server ip=%s:port=%d:id=%d\n", ????????????????inet_ntoa(sockaddr_client.sin_addr), sockaddr_client.sin_port, client_id);
????????????EnterCriticalSection(&cs_serve_thread);/*進入臨界區(qū)*/
????????????serve_client_thread_clear(sock_client, &sockaddr_client, client_id, buf, client_item_ptr);
????????????LeaveCriticalSection(&cs_serve_thread);/*離開臨界區(qū)*/
????????????ExitThread(0);/*退出線程*/ ????????} ????????printf("ip=%s:port=%d:id=%d say:%s\n", inet_ntoa(sockaddr_client.sin_addr), ????????????????sockaddr_client.sin_port, client_id, buf); ????}while( TRUE );
????return 0; } 2、客戶端代碼
頭文件:client.h#include <winsock2.h> #include <stdio.h> #include <windef.h>
#ifndef TCP_CLIENT_H #define TCP_CLIENT_H
#pragma warning(disable : 4996)
#define TCP_SERVER_ADDR "192.168.0.2" #define TCP_SERVER_PORT (60000) #define MAX_TCP_PACKET_SIZE (1492)/*tcp最大數(shù)據(jù)包字節(jié)數(shù)*/
#endif/*end TCP_CLIENT_H*/ 源文件:client.cpp#include "client.h"
int main() { ????int nRet = 0; ????WORD wVersionRequested;//版本號 ????WSADATA wsaData; ????SOCKET sock; ????SOCKADDR_IN server_addr; ????char buf[MAX_TCP_PACKET_SIZE]; ????int recv_size = 0; ???? ????wVersionRequested = MAKEWORD(1, 1);//1.1版本的套接字 ????nRet = WSAStartup(wVersionRequested, &wsaData); ????if( nRet ) ????{ ????????return nRet; ????} ???? ????if (LOBYTE(wsaData.wVersion) != 1 || ????????HIBYTE(wsaData.wVersion) != 1) ????{ ????????return -1; ????}//判斷高低字節(jié)是不是1,如果不是1.1的版本則退出???? ???? ????sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ????if( INVALID_SOCKET == sock ) ????{ ????????return -1; ????}
????server_addr.sin_addr.S_un.S_addr = inet_addr(TCP_SERVER_ADDR); ????server_addr.sin_family = AF_INET; ????server_addr.sin_port = htons(TCP_SERVER_PORT); ????nRet = connect(sock, (SOCKADDR*)&server_addr, sizeof(SOCKADDR) ); ????if( 0 != nRet ) ????{ ????????return nRet; ????}
????recv(sock, buf, sizeof(buf), 0); ????printf(buf);
????do ????{ ????????memset(buf, 0, sizeof(buf)); ????????printf("please write some thing:"); ????????gets(buf);
????????send(sock, buf, strlen(buf) + 1, 0); ????????if( ('q'== buf[0]) && (0 == buf[1]) ) ????????{ ????????????recv_size = recv(sock, buf, sizeof(buf), 0); ????????????printf(buf); ????????????break; ????????} ????}while( TRUE );
????closesocket(sock); ????WSACleanup();//必須調(diào)用這個函數(shù)清除參數(shù)
????return 0; }
總結(jié)
以上是生活随笔為你收集整理的vc简易网络服务器、客户端实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VC获取其他进程ListCtrl内容
- 下一篇: WCF与WebService的区别