Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1579039
  • 博文数量: 239
  • 博客积分: 1760
  • 博客等级: 上尉
  • 技术积分: 1595
  • 用 户 组: 普通用户
  • 注册时间: 2011-01-08 23:53
文章分类

全部博文(239)

文章存档

2016年(1)

2015年(28)

2014年(53)

2013年(42)

2012年(50)

2011年(65)

分类: WINDOWS

2011-05-06 00:24:20

一、服务器部分代码
头文件: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. }

阅读(1845) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~