您的位置:首页 > 其它

[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){}
}
其结果:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: