参考Programming Windows TCP Sockets in C++ for the Beginners(见codeproject), socket I/O模型选择WSAAsyncSelect进行编程时,参考代码有个bug:Server端第一次连接并读取Client端发送的buffer OK, 第二次就没有FD_READ事件了。
问题相关代码
WSAAsyncSelect (s, hwnd, 1045, FD_READ | FD_CONNECT | FD_CLOSE | FD_ACCEPT);
s(套接字)为全局变量。以上代码可以看到accept客户端连接替换的套接字与WSAAsyncSelect模型事件通知的套接字同一变量。
看看事件顺序
第一次客户端连接并发送buffer
FD_ACCEPT WSAAsyncSelect模型事件通知的套接字替换为accept客户端连接替换的套接字
FD_READ 从accept客户端连接替换的套接字读取buffer
FD_CLOSE 关闭客户端与Server的socket连接
第二次客户端连接并发送buffer
FD_ACCEPT 此时WSAAsyncSelect模型事件通知的套接字已经非法,使用accept从WSAAsyncSelect模型事件通知的套接字获取客户端连接套接字显示失败。
所以我们需要区分客户端连接替换的套接字与WSAAsyncSelect模型事件通知的套接字。
解决方案如下:
1、定义两个socket全局变量
SOCKET s; //WSAAsyncSelect模型事件通知的套接字同一变量
SOCKET c; //accept客户端连接替换的套接字
case FD_CLOSE: //Lost connection
if (c) closesocket(c);
break;
case FD_READ: //Incoming data to receive
static char buffer[80];
memset(buffer, 0, sizeof(buffer)); //Clear the buffer
recv (c, buffer, sizeof(buffer)-1, 0); //Get the text
break;
case FD_ACCEPT: //Connection request
{
char szAcceptAddr[100];
SOCKET TempSock = accept(s, (struct sockaddr*)&from, &fromlen);
c= TempSock; //Switch our old socket to the new one
break;
}