vc简易网络服务器、客户端实现

来源:互联网 发布:qq群淘宝客怎么赚钱 编辑:程序博客网 时间:2024/05/17 07:51
一、服务器部分代码头文件:server.h
  1. #include <winsock2.h>
  2. #include <stdio.h>
  3. #include <windef.h>
  4. #ifndef TCP_SERVER_H
  5. #define TCP_SERVER_H
  6. #pragma warning(disable : 4996)
  7. #define MAX_CLIENT (100)
  8. #define LISTEN_PORT (60000)
  9. #define CLIENT_TIMEOUT (15 * 60 * 60) /*客户端中断15分钟则服务器自动掉线*/
  10. #define MAX_TCP_PACKET_SIZE (1492)/*tcp最大数据包字节数*/
  11. typedef struct __client_item
  12. {
  13.     SOCKET client;
  14.     sockaddr_in form;
  15.     unsigned int id;
  16.     DWORD dwThreadId;
  17.     HANDLE hThread;
  18. }_client_item;
  19. typedef struct __client_list
  20. {
  21.     DWORD client_cnt;
  22.     _client_item client_item[MAX_CLIENT];
  23. }_client_list;
  24. DWORD WINAPI serve_client_thread_func( LPVOID param_ptr );
  25. #endif/*TCP_SERVER_H*/
源文件:server.cpp
  1. #include "server.h"
  2. #include <sys\stat.h>
  3. #include <time.h>
  4. _client_list client_list;
  5. CRITICAL_SECTION cs_serve_main;
  6. CRITICAL_SECTION cs_serve_thread;
  7. _client_list *get_client_list(void)
  8. {
  9.     return &client_list;
  10. }
  11. void client_list_cnt_inc(void)
  12. {
  13.     _client_list *client_list_ptr = get_client_list();
  14.     
  15.     client_list_ptr->client_cnt++;
  16. }
  17. void client_list_cnt_dec(void)
  18. {
  19.     _client_list *client_list_ptr = get_client_list();
  20.     client_list_ptr->client_cnt--;
  21. }
  22. unsigned int get_free_client_index(void)
  23. {
  24.     int i = 0;
  25.     unsigned int id = 0;
  26.     _client_list *client_list_ptr = get_client_list();
  27.     for(i = 0; i < MAX_CLIENT; i++)
  28.     {
  29.         id = client_list_ptr->client_item[i].id;
  30.         if( UINT_MAX == id )
  31.         {
  32.             break;
  33.         }
  34.     }
  35.     return i;
  36. }
  37. _client_item *get_client_item(unsigned int index)
  38. {
  39.     _client_list *client_list_ptr = get_client_list();
  40.     if( index >= MAX_CLIENT )
  41.     {
  42.         return NULL;
  43.     }
  44.     return &client_list_ptr->client_item[index];
  45. }
  46. void set_client_item(unsigned int index, _client_item *client_item_ptr)
  47. {
  48.     _client_list *client_list_ptr = get_client_list();
  49.     
  50.     if( index >= MAX_CLIENT )
  51.     {
  52.         return;
  53.     }
  54.     client_list_ptr->client_item[index] = *client_item_ptr;
  55. }
  56. SOCKET g_sk_server;
  57. int main()
  58. {
  59.     SOCKET server;
  60.     WSADATA wsaData;
  61.     sockaddr_in local;
  62.     int nRet = 0;
  63.     int sockaddr_in_sizeof = 0;
  64.     unsigned int index = 0;
  65.     _client_item *client_item_ptr = NULL;
  66.     _client_item client_item = {0};
  67.     _client_list *client_list_ptr = NULL;
  68.     SOCKET client;
  69.     sockaddr_in from;
  70.     DWORD dwThreadId;
  71.     HANDLE hThread;
  72.     nRet = WSAStartup(0x101, &wsaData);
  73.     if( 0 != nRet )
  74.     {
  75.         return 0;
  76.     }
  77.     
  78.     // 现在我们来为sockaddr_in结构赋值。
  79.     local.sin_family = AF_INET; // 地址族
  80.     local.sin_addr.s_addr = INADDR_ANY; // 网际IP地址
  81.     local.sin_port = htons(LISTEN_PORT); // 使用的端口
  82.     // 由socket函数创建我们的SOCKET。
  83.     server = socket(AF_INET, SOCK_STREAM, 0);
  84.     //server = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,NULL, 0, WSA_FLAG_OVERLAPPED);
  85.     // 如果socket()函数失败,我们就退出。
  86.     if( server == INVALID_SOCKET )
  87.     {
  88.         return 0;
  89.     }
  90.     // bind将我们刚创建的套接字和sockaddr_in结构联系起来。
  91.     // 它主要使用本地地址及一个特定的端口来连接套接字。
  92.     // 如果它返回非零值,就表示出现错误。
  93.     nRet = bind(server, (sockaddr*)&local, sizeof(local));
  94.     if( 0 != nRet )
  95.     {
  96.         return 0;
  97.     }
  98.     // listen命令套接字监听来自客户端的连接。
  99.     // 第二个参数是最大连接数。
  100.     nRet = listen(server, MAX_CLIENT);
  101.     if( 0 != nRet )
  102.     {
  103.         return 0;
  104.     }
  105.     g_sk_server = server;
  106.     // 我们需要一些变量来保存客户端的套接字,因此我们在此声明之。
  107.     InitializeCriticalSection(&cs_serve_main);/*初始化临界区*/
  108.     InitializeCriticalSection(&cs_serve_thread);/*初始化临界区*/
  109.     client_list_ptr = get_client_list();
  110.     memset(client_list_ptr, 0xff, sizeof(_client_list));
  111.     memset(&client, 0, sizeof(SOCKET));
  112.     memset(&from, 0, sizeof(sockaddr_in));
  113.     sockaddr_in_sizeof = sizeof(sockaddr_in);
  114.     while( TRUE )
  115.     {
  116.         index = get_free_client_index();
  117.         if( index >= MAX_CLIENT )
  118.         {/*已经达到最大连接数*/
  119.             continue;
  120.         }
  121.         client_item_ptr = get_client_item(index);
  122.         client_item_ptr->client = accept(server,
  123.             (struct sockaddr*)&client_item_ptr->form, &sockaddr_in_sizeof);
  124.         if( INVALID_SOCKET == client_item_ptr->client )
  125.         {/*连接错误*/
  126.             Sleep(500);
  127.             continue;
  128.         }else
  129.         {
  130.             printf("Connection from %s\n", inet_ntoa(client_item_ptr->form.sin_addr) );
  131.         }
  132.         /* 多线程开始*/
  133.         EnterCriticalSection(&cs_serve_main);/*进入临界区*/
  134.         hThread = CreateThread(
  135.             NULL, // no security attributes
  136.             0, // use default stack size
  137.             serve_client_thread_func, // thread function
  138.             client_item_ptr, // argument to thread function
  139.             CREATE_SUSPENDED, // use default creation flags
  140.             &dwThreadId); // returns the thread identifier
  141.         if( NULL != hThread )
  142.         {
  143.             client_item_ptr->hThread = hThread;
  144.             client_item_ptr->dwThreadId = dwThreadId;
  145.             client_item_ptr->id = index;
  146.         }
  147.         client_list_cnt_inc();
  148.         LeaveCriticalSection(&cs_serve_main);/*离开临界区*/
  149.         if( NULL != client_item_ptr->hThread )
  150.         {
  151.             ResumeThread(client_item_ptr->hThread);
  152.         }
  153.         client_item_ptr = NULL;
  154.         /*end 多线程开始*/
  155.     }
  156.     //关闭套接字,并释放套接字描述符。
  157.     closesocket(server);
  158.     WSACleanup();
  159.     DeleteCriticalSection(&cs_serve_thread);/*删除临界区*/
  160.     DeleteCriticalSection(&cs_serve_main);/*删除临界区*/
  161.     return 0;
  162. }
  163. void serve_client_thread_clear(SOCKET sock_client,
  164.                                sockaddr_in *sockaddr_client_ptr,
  165.                                UINT32 client_id,
  166.                                char *msg,
  167.                                _client_item *client_item_ptr
  168.                                )
  169. {
  170.     int msg_len = strlen(msg);
  171.     if( msg_len > 0 )
  172.     {
  173.         send(sock_client, msg, msg_len + 1, 0);
  174.     }
  175.     closesocket(sock_client);/*关闭连接*/
  176.     client_list_cnt_dec();
  177.     
  178.     memset(client_item_ptr, 0, sizeof(_client_item));
  179.     set_client_item(client_id, client_item_ptr);
  180. }
  181. DWORD WINAPI serve_client_thread_func(LPVOID param_ptr)
  182. {
  183.     char buf[MAX_TCP_PACKET_SIZE];
  184.     _client_item *client_item_ptr = (_client_item *)param_ptr;
  185.     SOCKET sock_client = 0;
  186.     sockaddr_in sockaddr_client = {0};
  187.     unsigned int client_id = 0;
  188.     _client_list *client_list_ptr = get_client_list();
  189.     int recv_size = 0;
  190.     time_t sock_free_cur_time = 0;
  191.     time_t sock_free_kill_time = 0;
  192.     
  193.     int n_ret = 0;
  194.     fd_set fdread;
  195.     timeval tv;
  196.     while( NULL == client_item_ptr->hThread );
  197.     sock_client = client_item_ptr->client;
  198.     sockaddr_client = client_item_ptr->form;
  199.     client_id = client_item_ptr->id;
  200.     sprintf(buf, "%s:%d you id=%d\n", inet_ntoa(sockaddr_client.sin_addr),
  201.         sockaddr_client.sin_port, client_id);
  202.     send(sock_client, buf, strlen(buf) + 1, 0);
  203.     do
  204.     {
  205.         /*这部分代码在此处必须每次都执行*/
  206.         FD_ZERO(&fdread);//初始化fd_set
  207.         FD_SET(sock_client, &fdread);//分配套接字句柄到相应的fd_set
  208.         tv.tv_sec = 1;//这里我们打算让select等待1s后返回,避免被锁死,也避免马上返回
  209.         tv.tv_usec = 0;
  210.         /*end 这部分代码在此处必须每次都执行*/
  211.         select(0, &fdread, NULL, NULL, &tv);
  212.         n_ret = FD_ISSET(sock_client, &fdread);
  213.         if( 0 == n_ret )/*没有数据*/
  214.         {
  215.             continue;
  216.         }
  217.         recv_size = recv(sock_client, buf, sizeof(buf), 0);
  218.         if( recv_size <= 0)
  219.         {/*socket 错误,断开连接并退出*/
  220.             /*超时,线程退出*/
  221.             printf("client time out ip=%s:port=%d:id=%d\n",
  222.                 inet_ntoa(sockaddr_client.sin_addr), sockaddr_client.sin_port, client_id);
  223.             EnterCriticalSection(&cs_serve_thread);/*进入临界区*/
  224.             memset(buf, 0, sizeof(buf));
  225.             serve_client_thread_clear(sock_client, &sockaddr_client, client_id, buf, client_item_ptr);
  226.             LeaveCriticalSection(&cs_serve_thread);/*离开临界区*/
  227.             ExitThread(0);/*退出线程*/
  228.         }
  229.         sock_free_cur_time = 0;
  230.         if( ('q' == buf[0]) && (0 == buf[1]) )
  231.         {/*客户端主动退出*/
  232.             sprintf(buf, "client exit server ip=%s:port=%d:id=%d\n",
  233.                 inet_ntoa(sockaddr_client.sin_addr), sockaddr_client.sin_port, client_id);
  234.             EnterCriticalSection(&cs_serve_thread);/*进入临界区*/
  235.             serve_client_thread_clear(sock_client, &sockaddr_client, client_id, buf, client_item_ptr);
  236.             LeaveCriticalSection(&cs_serve_thread);/*离开临界区*/
  237.             ExitThread(0);/*退出线程*/
  238.         }
  239.         printf("ip=%s:port=%d:id=%d say:%s\n", inet_ntoa(sockaddr_client.sin_addr),
  240.                 sockaddr_client.sin_port, client_id, buf);
  241.     }while( TRUE );
  242.     return 0;
  243. }
2、客户端代码头文件:client.h
  1. #include <winsock2.h>
  2. #include <stdio.h>
  3. #include <windef.h>
  4. #ifndef TCP_CLIENT_H
  5. #define TCP_CLIENT_H
  6. #pragma warning(disable : 4996)
  7. #define TCP_SERVER_ADDR "192.168.0.2"
  8. #define TCP_SERVER_PORT (60000)
  9. #define MAX_TCP_PACKET_SIZE (1492)/*tcp最大数据包字节数*/
  10. #endif/*end TCP_CLIENT_H*/
源文件:client.cpp
  1. #include "client.h"
  2. int main()
  3. {
  4.     int nRet = 0;
  5.     WORD wVersionRequested;//版本号
  6.     WSADATA wsaData;
  7.     SOCKET sock;
  8.     SOCKADDR_IN server_addr;
  9.     char buf[MAX_TCP_PACKET_SIZE];
  10.     int recv_size = 0;
  11.     
  12.     wVersionRequested = MAKEWORD(1, 1);//1.1版本的套接字
  13.     nRet = WSAStartup(wVersionRequested, &wsaData);
  14.     if( nRet )
  15.     {
  16.         return nRet;
  17.     }
  18.     
  19.     if (LOBYTE(wsaData.wVersion) != 1 ||
  20.         HIBYTE(wsaData.wVersion) != 1)
  21.     {
  22.         return -1;
  23.     }//判断高低字节是不是1,如果不是1.1的版本则退出    
  24.     
  25.     sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  26.     if( INVALID_SOCKET == sock )
  27.     {
  28.         return -1;
  29.     }
  30.     server_addr.sin_addr.S_un.S_addr = inet_addr(TCP_SERVER_ADDR);
  31.     server_addr.sin_family = AF_INET;
  32.     server_addr.sin_port = htons(TCP_SERVER_PORT);
  33.     nRet = connect(sock, (SOCKADDR*)&server_addr, sizeof(SOCKADDR) );
  34.     if( 0 != nRet )
  35.     {
  36.         return nRet;
  37.     }
  38.     recv(sock, buf, sizeof(buf), 0);
  39.     printf(buf);
  40.     do
  41.     {
  42.         memset(buf, 0, sizeof(buf));
  43.         printf("please write some thing:");
  44.         gets(buf);
  45.         send(sock, buf, strlen(buf) + 1, 0);
  46.         if( ('q'== buf[0]) && (0 == buf[1]) )
  47.         {
  48.             recv_size = recv(sock, buf, sizeof(buf), 0);
  49.             printf(buf);
  50.             break;
  51.         }
  52.     }while( TRUE );
  53.     closesocket(sock);
  54.     WSACleanup();//必须调用这个函数清除参数
  55.     return 0;
  56. }
0 0
原创粉丝点击