本文作者:sodme 本文出处:http://blog.csdn.net/sodme
版权声明:本文可以不经作者同意任意转载,但转载时烦请保留文章开始前两行的版权、作者及出处信息。
对于初次使用IOCP进行高性能服务器开发的朋友来说,可能会经常遇到一些莫名其妙的错误,让自己无从下手。为此,我将利用此篇文章对IOCP开发中的常见问题予以集中记录并持续添加,并附上我的处理建议,以供大家参考。
1、在程序创建监听套接字时,使用socket函数创建一个套接字时,总是报“INVALID_SOCKET”错误?
原因:出现此问题的原因,很可能是因为没有正确执行WSAStartUp函数引起的;
解决方法:请检查,是否使用WSAStartUp对winsock进行了初始化工作?如果进行了初始化,请检查初始化是否成功?
2、使用WSASend或WSARecv投递相应的发送或接收请求后,始终没有收到相应的GET函数完成返回通知?
原因:出现此问题的原因,绝大多数是因为函数参数没有进行正确的赋值。
解决方法:在执行wsasend和wsarecv操作前,请先将overlapped结构体使用memset进行清零。一个正确的调用格式如下:
[发送操作]
DWORD ByteSend=0;
DWORD Flags=0;
int tmpResult=0;
......
PPerHandleData tmpData;
......
memset(&(tmpData->Overlapped), '/0', sizeof(OVERLAPPED));//将overlapped结构清空
tmpData->Statu = ssSend;
tmpResult = WSASend(tmpData->socket, &(tmpData->WSASendBuffer), 1,
&ByteSend,
Flags,
&(tmpData->Overlapped),
NULL);
[接收操作]
DWORD byteRecv=0;
DWORD Flags=0;
int tmpResult=0;
......
PPerHandleData myHandlData;
......
memset(&(myHandlData->Overlapped), '/0', sizeof(OVERLAPPED));
memset(myHandlData->RecvBuffer, '/0', CLIENT_BUFFER_SIZE);
myHandlData->WSARecvBuffer.buf = myHandlData->RecvBuffer;
myHandlData->WSARecvBuffer.len = CLIENT_BUFFER_SIZE;
myHandlData->socket = myClient->m_ClientSocket;
myHandlData->Statu = ssRecv;
tmpResult = WSARecv(myHandlData->socket, &(myHandlData->WSARecvBuffer), 1, (LPDWORD)&byteRecv, (LPDWORD)&Flags, (LPWSAOVERLAPPED)&(myHandlData->Overlapped), 0);
3、当投递了一个WSARecv或WSASend请求后,总是返回“ERROR_IO_PENDING”错误?
原因:“ERROR_IO_PENDING”,表示的是WSARecv或WSASend操作正在执行中,还没有执行完毕。
解决方法:此错误可以直接忽略,如果参数设置正确,当操作完成时,系统会通过GET函数返回执行的形式来通知发送或接收操作已经完成。
4、为什么投递一个WSASend操作后,在Get函数中,获得发送完成事件的通知时,截获到的发送出去的数据却不是刚刚投递的数据?
原因:在投递WSASend时,会要求你指定数据缓冲区的地址,如果你此处的地址是通过new动态分配的,并且在投递过WSASend之后随之即delete了此空间,则可能会发生你的描述的这个现象。我的理解是:当WSASend操作还没有真正完成时,如果释放了数据缓冲区,那么WSASend将会因为缓冲区的释放而造成没有正确投递缓冲区内的数据,也就是说,WSASend在投递一个数据时,并没有即刻把数据拷到投递缓冲区去,如果是在WSASend完成后再释放此空间则不会发生这种情况。
5、一个误解: 单个服务器程序可承受最大连接数“理论”上是“65535”
请注意,这里有两个词分别被我标记上了引号,一个是“理论”,一个是“65535”。强调“理论”这个词,是想特别明确误解者的意思:就是说,这个值是不可能被打破的,是铁板钉丁的。而65535这个数字的由来,很多人想当然地将它与port最大值联系起来。的确,TCP的端口数,最大值确实为65535。但是,这并不代表一个服务器可以接受的连接数就是这个值,很多人之所以把这两个概念搞混淆是因为对socket和port没有更深的认识和理解。我们先来回想一下服务器服务的先后过程:服务器创建监听socket->与对外服务的端口号绑定->开始listen->客户端连接到服务器对应的port->服务器accept为新的客户端产生新的socket->基于这个新的socket与客户端交换数据。从以上流程来看,最大值为65535的“端口号”这个重要的东东,我们只用了一次,就是执行bind的时候!而以后创建的socket,说白了就是一个可以进行网络IO操作的HANDLE而已,它跟端口号的牵扯仅限bind以及作为客户端连接服务器的识别端口号的时候,一旦accept产生了socket,这个端口号,对服务器和新客户端的通信而言就不再有任何意义。而服务器可承载的连接数最大量,不就是能产生多少个客户端的socket吗?这个socket值即使与端口号无关,又何来65535的“理论”上限?我再一次地将“理论”二字用引号括起,是因为在有的操作系统中,默认的配置会将socket最大值设定为65535,但这个值是可以改的!