阻塞模式下的多线程编程
由于send recv等函数的阻塞,将会导致主程序一直在等待某个send或者recv调用结束,才会处理其他的事情,那么多客户端与服务器的通信将变得无法完成。此时将引用线程的方式来解决这一问题。
一个简单的多客户端与服务器通信
server.cpp
SOCKET sock_listen;
SOCKET talk;
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested= MAKEWORD( 2, 2 );
int err = WSAStartup( wVersionRequested, &wsaData);
if ( err != 0 )
return FALSE;
if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE(wsaData.wVersion ) != 2 )
{
WSACleanup();
return FALSE;
}
if (INVALID_SOCKET == (sock_listen = socket(AF_INET,SOCK_STREAM, 0)))
{
printf("创建套接字失败\n");
return FALSE;
}
printf(""创建套接字成功n");
sockaddr_insrv_addr;
memset(&srv_addr,0, sizeof(sockaddr));
srv_addr.sin_family= AF_INET;
srv_addr.sin_port= htons(6000);
srv_addr.sin_addr.S_un.S_addr= htonl(INADDR_ANY);
if (SOCKET_ERROR == bind(sock_listen, (sockaddr*)&srv_addr,sizeof(sockaddr)))
{
printf("监听套接字失败\n");
return FALSE;
}
printf("监听套接字成功\n");
listen(sock_listen,SOMAXCONN);
printf("监¨听成功......\n");
while (1)
{
SOCKETtalk;
sockaddr_inclient_addr;
int len = sizeof(sockaddr);
if (INVALID_SOCKET == (talk = accept(socket_listen, (sockaddr*)&client_addr, &len)))
{
printf("接收套接字失败\n");
return;
}
CreateThread(NULL, 0, RequstProc, (LPVOID)&talk 0, NULL);
//主程序在不断接受来自客户端的连接后,创建线程为每个客户端处理数据的传输。
}
补充一点:很疑惑的是我们定义的socket_listen的端口号是6000,那么每次连接accpet成功后的talk套接字是不是都是6000呢?答案是肯定的。具体可以查一下网络层
DWORD WINAPI RequstProc(LPVOID lpParameter)
{
DWORD dwTid = GetCurrentThreadId();
printf("SendFile(%d) is ok\n",dwTid);
// 获得参数sokcet
SOCKET ClientSendSocket = (SOCKET)lpParameter;
//TODO:开始处理一些数据传输
}
另外可以使用多端口的方式,可以处理多客户并发从服务器传文件或者下载文件的问题。
在上述的requesteProc线程里面,我们可以再创建一个发送线程,和接收线程。
发送线程,在创建一个端口号7000,并一直在while(true)循环中accpet来自客户端的recv线程中的连接请求,同样客户端的recv线程也是创建一个7000的端口进行连接。等待连接结束之后,在此线程基础上,再次开辟线程用于处理数据的交换。