您当前的位置: 首页 >  网络

phymat.nico

暂无认证

  • 4浏览

    0关注

    1967博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

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

phymat.nico 发布时间:2015-01-08 11:56:49 ,浏览量:4

一、服务器部分代码
头文件:server.h
 
 
  1. #include
  2. #include
  3. #include
  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
  3. #include
  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
关注
打赏
1659628745
查看更多评论
立即登录/注册

微信扫码登录

0.0431s