[Win32]处理并发的客户端连接
2013-05-16 21:35
274 查看
并发的客户端连接
服务器端在监听是需要指定一个端口,这个端口可以接收多个客户端的连接。客户端在连接服务器端时,本机的端口不需要指定,系统会自动选取一个当前不用的端口与服务器端的固定端口连接。在同一时刻可以有多个不同主机上的客户端连接到服务器端,一个主机上也可以同时有多个客户端连接到同一个服务器端,但是在建立连接时,socket()会为客户端分配不同的端口。客户端不会使用同一端口和同一服务端建立多次连接。
服务端程序使用accept()接收客户端的连接。因此如果服务器端需要有与多个客户端连接时,在accept()返回后,一个连接已经建立后需要立即再调用accept(),等待其他客户端的连接。如果客户端连接时,而服务器端程序此时如果没有调用accept(),那么连接不会成功建立。
因此处理并发客户端连接的服务器必定是多线程的。监听程序最好事呀单独的线程,而且为了对每个客户端的请求都能理解响应,每个与客户端的连接最好建立至少有一个线程处理数据的发送和接收。
服务器的程序
新建win32项目控制台程序 Win32Server项目:用于解决并发的客户端连接问题// Win32Server.cpp : 定义控制台应用程序的入口点。 #include "stdafx.h" #include <WinSock2.h> #include <ws2tcpip.h> #pragma comment(lib,"wsock32.lib") #pragma comment(lib,"ws2_32.lib") #define DEFPORT "10000" //处理接收的消息 void HandleMsg(SOCKET sockfd,char* msg) { int nSend=0; char sendBuf[2048]={0}; if (lstrcmpiA(msg,"download") == 0) { strcpy(sendBuf,"we get downLoad\n"); } else if (lstrcmpiA(msg,"get information") == 0) { strcpy(sendBuf,"we get information!!!!\n"); } nSend=send(sockfd,sendBuf,strlen(sendBuf),0); if (nSend == SOCKET_ERROR) { printf("error at send(),threadID=%d, errno=%d\n",sockfd,WSAGetLastError()); closesocket(sockfd); } printf("sockID=%d,send client [%d]bytes----%s",sockfd,nSend,sendBuf); } //已连接线程函数,用于接收发送消息 DWORD WINAPI ConnectedThreadFun(LPVOID lpParam) { DWORD dwThreadID=GetCurrentProcessId(); SOCKET sockfd=(SOCKET)lpParam; int recvByte=0; char recvBuf[2096]; recvByte=recv(sockfd,recvBuf,strlen(recvBuf)+1,0); if (recvByte == 0)//接收数据失败,连接关闭 { printf("因接收的数据量为0,故接收数据失败,连接关闭!!!"); closesocket(sockfd); return 0; } else if (recvByte == SOCKET_ERROR)//接收数据失败,socket错误 { printf("error at recv,erron=%d\n",WSAGetLastError()); closesocket(sockfd); return 0; } else if (recvByte > 0) { printf("ConnectedThreadFunID(%d),[%d] Bytes received:%s\n",dwThreadID,recvByte,recvBuf); HandleMsg(sockfd,recvBuf); } closesocket(sockfd); return 0; } //等待连接线程 DWORD WINAPI WaitForConnectionThreadFun(LPVOID lpParam) { SOCKET listenSocket=(SOCKET)lpParam; SOCKET clientSocket=INVALID_SOCKET; SOCKADDR_IN clientAddr; int clientAddrLen=sizeof(clientAddr); while(1) { printf("WaitForConnectionThreadFun threadID=%d,ready to accept\n",GetCurrentThreadId()); clientSocket=accept(listenSocket,(SOCKADDR*)&clientAddr,&clientAddrLen); if(clientSocket == INVALID_SOCKET) { printf("error at accept(),errno=%d\n",WSAGetLastError()); closesocket(listenSocket); return 0;//等待连接错误,退出循环 } printf("accept a connetion[%s]:%d,sockfd=%d\n\n\n",inet_ntoa(clientAddr.sin_addr),ntohs(clientAddr.sin_port),clientSocket); //为每一个连接创建一个数据发送的接收线程,使服务端又可以立即接收其他的客户端连接 if (!CreateThread(NULL,0,ConnectedThreadFun,(LPVOID)clientSocket,0,NULL)) { printf("error at create ConnectedThreadFun,error(%d)\n",GetLastError()); closesocket(listenSocket); return 0; } } return 0; } void main() { WSADATA data; if(WSAStartup(MAKEWORD(2,2),&data) != NO_ERROR) { printf("error at WSAStartup,errno=%d\n",GetLastError()); return; } SOCKET listenSocket=INVALID_SOCKET;//当然此变量需要是全局变量 if((listenSocket=socket(AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET) { printf("error at socket(),errno=%d\n",WSAGetLastError()); WSACleanup(); return; } printf("socket successfully!!!\n"); addrinfo *result=NULL,hints; ZeroMemory(&hints,sizeof(hints)); SOCKADDR_IN dd; hints.ai_family=AF_INET; hints.ai_socktype=SOCK_STREAM; hints.ai_socktype=0; hints.ai_flags=AI_PASSIVE; if(getaddrinfo(NULL,DEFPORT,&hints,&result) != 0) { printf("error at getaddrinfo\n"); closesocket(listenSocket); WSACleanup(); return; } if (bind(listenSocket,result->ai_addr,result->ai_addrlen) == SOCKET_ERROR) { printf("error at bind(),errno=%d\n",WSACleanup()); freeaddrinfo(result); closesocket(listenSocket); WSACleanup(); return; } freeaddrinfo(result);//result不再需要 printf("bind successfully!!!\n"); if (listen(listenSocket,SOMAXCONN) == SOCKET_ERROR) { printf("error at listen(),errno=%d\n",WSACleanup()); closesocket(listenSocket); WSACleanup(); return; } printf("listen successfully!!!\n"); if (!CreateThread(NULL,0,WaitForConnectionThreadFun,(LPVOID)listenSocket,0,NULL)) { printf("error at create WaitForConnectionThreadFun,errno=%d\n",GetLastError()); closesocket(listenSocket); WSACleanup(); return; } //添加了等待连接线程,可以继续往下执行程序,也可以解决客户端并发连接问题 while(1){} }其结果:
相关文章推荐
- [Win32]处理并发的客户端连接
- 5. 使用fork并发处理多个客户端的连接程序
- [转]The C10K problem(中文版) - 如何处理高并发连接
- socket支持多客户端连接以及多并发
- QTcpServer使用信号槽单线程方式直接处理连进来的客户端(短连接或少数据处理)
- 使用epoll处理并发socket连接
- CentOS下SVN服务器运行,windows作为客户端连接SVN服务器失败的处理
- Python处理多个客户端连接---线程服务器
- Redis 如何处理客户端连接
- live555 接收客户端连接及rtsp交互---网络连接处理及RTSP连接模块 .
- Redis如何处理客户端连接
- 准多线程TCP服务器,处理客户端连接请求。
- Photon——Client Connection Handling 客户端连接处理
- 客户端连接服务器端后sysdate时间不正确的处理
- Redis如何处理客户端连接
- Redis基础知识之————如何处理客户端连接
- Windows平台下Oracle 11g R2监听文件日志过大,造成客户端无法连接的问题处理
- 客户端与服务器端TCP连接,关闭连接时应作的处理
- MysSQL处理客户端连接与skip-name-resolve关系
- 处理大并发之二 对epoll的理解,epoll客户端服务端代码