[Win32]处理并发的客户端连接

并发的客户端连接

服务器端在监听是需要指定一个端口,这个端口可以接收多个客户端的连接。客户端在连接服务器端时,本机的端口不需要指定,系统会自动选取一个当前不用的端口与服务器端的固定端口连接。

在同一时刻可以有多个不同主机上的客户端连接到服务器端,一个主机上也可以同时有多个客户端连接到同一个服务器端,但是在建立连接时,socket()会为客户端分配不同的端口。客户端不会使用同一端口和同一服务端建立多次连接。

服务端程序使用accept()接收客户端的连接。因此如果服务器端需要有与多个客户端连接时,在accept()返回后,一个连接已经建立后需要立即再调用accept(),等待其他客户端的连接。如果客户端连接时,而服务器端程序此时如果没有调用accept(),那么连接不会成功建立。

因此处理并发客户端连接的服务器必定是多线程的。监听程序最好事呀单独的线程,而且为了对每个客户端的请求都能理解响应,每个与客户端的连接最好建立至少有一个线程处理数据的发送和接收。

服务器的程序

新建win32项目控制台程序 Win32Server项目:用于解决并发的客户端连接问题
[cpp]  view plain copy
  1. // Win32Server.cpp : 定义控制台应用程序的入口点。   
  2.   
  3. #include "stdafx.h"  
  4. #include <WinSock2.h>  
  5. #include <ws2tcpip.h>  
  6.   
  7. #pragma comment(lib,"wsock32.lib")  
  8. #pragma comment(lib,"ws2_32.lib")   
  9. #define  DEFPORT "10000"  
  10. //处理接收的消息  
  11. void HandleMsg(SOCKET sockfd,char* msg)  
  12. {  
  13.     int nSend=0;  
  14.     char sendBuf[2048]={0};   
  15.     if (lstrcmpiA(msg,"download") == 0)  
  16.     {         
  17.         strcpy(sendBuf,"we get downLoad\n");  
  18.     }  
  19.     else if (lstrcmpiA(msg,"get information") == 0)  
  20.     {   
  21.         strcpy(sendBuf,"we get information!!!!\n");  
  22.     }  
  23.     nSend=send(sockfd,sendBuf,strlen(sendBuf),0);  
  24.     if (nSend == SOCKET_ERROR)  
  25.     {  
  26.         printf("error at send(),threadID=%d, errno=%d\n",sockfd,WSAGetLastError());  
  27.         closesocket(sockfd);  
  28.     }  
  29.     printf("sockID=%d,send client [%d]bytes----%s",sockfd,nSend,sendBuf);   
  30. }  
  31. //已连接线程函数,用于接收发送消息  
  32. DWORD WINAPI ConnectedThreadFun(LPVOID lpParam)  
  33. {  
  34.     DWORD dwThreadID=GetCurrentProcessId();  
  35.     SOCKET sockfd=(SOCKET)lpParam;  
  36.     int recvByte=0;  
  37.     char recvBuf[2096];  
  38.     recvByte=recv(sockfd,recvBuf,strlen(recvBuf)+1,0);  
  39.     if (recvByte == 0)//接收数据失败,连接关闭  
  40.     {  
  41.         printf("因接收的数据量为0,故接收数据失败,连接关闭!!!");  
  42.         closesocket(sockfd);  
  43.         return 0;  
  44.     }  
  45.     else if (recvByte == SOCKET_ERROR)//接收数据失败,socket错误  
  46.     {  
  47.         printf("error at recv,erron=%d\n",WSAGetLastError());  
  48.         closesocket(sockfd);  
  49.         return 0;  
  50.     }  
  51.     else if (recvByte > 0)  
  52.     {  
  53.         printf("ConnectedThreadFunID(%d),[%d] Bytes received:%s\n",dwThreadID,recvByte,recvBuf);  
  54.         HandleMsg(sockfd,recvBuf);  
  55.     }  
  56.     closesocket(sockfd);  
  57.     return 0;  
  58. }  
  59. //等待连接线程  
  60. DWORD WINAPI WaitForConnectionThreadFun(LPVOID lpParam)  
  61. {  
  62.     SOCKET listenSocket=(SOCKET)lpParam;  
  63.     SOCKET clientSocket=INVALID_SOCKET;  
  64.     SOCKADDR_IN clientAddr;  
  65.     int clientAddrLen=sizeof(clientAddr);  
  66.     while(1)  
  67.     {  
  68.         printf("WaitForConnectionThreadFun threadID=%d,ready to accept\n",GetCurrentThreadId());  
  69.         clientSocket=accept(listenSocket,(SOCKADDR*)&clientAddr,&clientAddrLen);  
  70.         if(clientSocket == INVALID_SOCKET)  
  71.         {  
  72.             printf("error at accept(),errno=%d\n",WSAGetLastError());  
  73.             closesocket(listenSocket);  
  74.             return 0;//等待连接错误,退出循环  
  75.         }   
  76.         printf("accept a connetion[%s]:%d,sockfd=%d\n\n\n",inet_ntoa(clientAddr.sin_addr),ntohs(clientAddr.sin_port),clientSocket);  
  77.         //为每一个连接创建一个数据发送的接收线程,使服务端又可以立即接收其他的客户端连接  
  78.         if (!CreateThread(NULL,0,ConnectedThreadFun,(LPVOID)clientSocket,0,NULL))  
  79.         {  
  80.             printf("error at create ConnectedThreadFun,error(%d)\n",GetLastError());  
  81.             closesocket(listenSocket);  
  82.             return 0;  
  83.         }  
  84.     }  
  85.     return 0;  
  86. }  
  87. void main()  
  88. {  
  89.     WSADATA data;  
  90.     if(WSAStartup(MAKEWORD(2,2),&data) != NO_ERROR)  
  91.     {  
  92.         printf("error at WSAStartup,errno=%d\n",GetLastError());  
  93.         return;  
  94.     }   
  95.     SOCKET listenSocket=INVALID_SOCKET;//当然此变量需要是全局变量  
  96.     if((listenSocket=socket(AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET)  
  97.     {  
  98.         printf("error at socket(),errno=%d\n",WSAGetLastError());  
  99.         WSACleanup();  
  100.         return;  
  101.     }  
  102.     printf("socket successfully!!!\n");  
  103.        
  104.     addrinfo *result=NULL,hints;  
  105.     ZeroMemory(&hints,sizeof(hints));  
  106.     SOCKADDR_IN dd;  
  107.     hints.ai_family=AF_INET;  
  108.     hints.ai_socktype=SOCK_STREAM;  
  109.     hints.ai_socktype=0;  
  110.     hints.ai_flags=AI_PASSIVE;  
  111.     if(getaddrinfo(NULL,DEFPORT,&hints,&result) != 0)   
  112.     {  
  113.         printf("error at getaddrinfo\n");  
  114.         closesocket(listenSocket);  
  115.         WSACleanup();  
  116.         return;  
  117.     }  
  118.   
  119.     if (bind(listenSocket,result->ai_addr,result->ai_addrlen) == SOCKET_ERROR)  
  120.     {  
  121.         printf("error at bind(),errno=%d\n",WSACleanup());  
  122.         freeaddrinfo(result);  
  123.         closesocket(listenSocket);  
  124.         WSACleanup();  
  125.         return;  
  126.     }  
  127.     freeaddrinfo(result);//result不再需要  
  128.     printf("bind successfully!!!\n");  
  129.   
  130.     if (listen(listenSocket,SOMAXCONN) == SOCKET_ERROR)  
  131.     {  
  132.         printf("error at listen(),errno=%d\n",WSACleanup());   
  133.         closesocket(listenSocket);  
  134.         WSACleanup();  
  135.         return;  
  136.     }  
  137.     printf("listen successfully!!!\n");  
  138.   
  139.     if (!CreateThread(NULL,0,WaitForConnectionThreadFun,(LPVOID)listenSocket,0,NULL))  
  140.     {  
  141.         printf("error at create WaitForConnectionThreadFun,errno=%d\n",GetLastError());  
  142.         closesocket(listenSocket);  
  143.         WSACleanup();  
  144.         return;  
  145.     }  
  146.     //添加了等待连接线程,可以继续往下执行程序,也可以解决客户端并发连接问题  
  147.     while(1){}  
  148. }  
其结果:

此文章来自于【http://blog.csdn.net/ouyangshima/article/details/8936978】
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值