IOCP客户端ConnectEx,GetQueuedCompletionStatus返回52错误
一个IOCP的程序,因为有转发功能,所以IOCP的服务端和客户端封装在同一个程序模块中,做为客户端,采用ConnectEx来做连接。做压力测试,上一级客户端并发2000个连接到这个IOCP程序,IOCP服务端收到数据后利用本程序的IOCP客户端转发数据到下一级服务器,在做大并发时,ConnectEx操作投递时能够正确返回,但是从GetQueuedCompletionStatus获取结果时返回错误,错误码52:ERROR_DUP_NAME(由于网络上有重名,没有连接。请到“控制面板”中的“系统”更改计算机名,然后重试。)
这个问题在大并发时并不是每个连接都会出现此错误,但是出现的几率也不小。以下是ConnectEx处的代码:
SOCKET ClientSocket = INVALID_SOCKET;
ClientSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP,
NULL, 0, WSA_FLAG_OVERLAPPED);
if (INVALID_SOCKET == ClientSocket)
{
cout << "WSASocket() failed: " << WSAGetLastError() << endl;
WSACleanup();
return FALSE;
}
SOCKADDR_IN local;
local.sin_family = AF_INET;
local.sin_addr.S_un.S_addr = INADDR_ANY;
local.sin_port = 0;
if(SOCKET_ERROR == bind(ClientSocket, (LPSOCKADDR)&local, sizeof(local)))
{
int iError = GetLastError();
printf("绑定套接字失败! %d \r\n",iError);
getchar();
return FALSE;
}
PER_IO_CONTEXT *pmyoverlapped = (PPER_IO_CONTEXT)HeapAlloc(\
GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PER_IO_CONTEXT)); // socket 和I/O 通讯的载体
pmyoverlapped ->IoOperation = IoConnect ; // 设置请求类型,得到I/O 结果时根据此来识别请求类型
pmyoverlapped ->sClient = ClientSocket;
pmyoverlapped ->pNext = NULL;
//
//为监听套接字分配一个单句柄数据
//
PPER_HANDLE_CONTEXT lpListenHandleContext = NULL;
lpListenHandleContext = (PPER_HANDLE_CONTEXT)HeapAlloc(
GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(PER_HANDLE_CONTEXT)
);
if (NULL == lpListenHandleContext)
{
closesocket(ClientSocket);
WSACleanup();
cout << "HeapAlloc() failed " << endl;
return FALSE;
}
lpListenHandleContext->IoSocket = ClientSocket;
lpListenHandleContext->pNext = NULL;
//
//将监听套接字m_ListenSocket和已经建立的完成端口关联起来
//
HANDLE hrc = CreateIoCompletionPort(
(HANDLE)ClientSocket,
m_hCOP,
(ULONG_PTR)lpListenHandleContext,
0
);
if (NULL == hrc)
{
closesocket(ClientSocket);
HeapFree(GetProcessHeap(), 0, lpListenHandleContext);
WSACleanup();
cout << "CreateIoCompletionPort failed: " << GetLastError() << endl;
return FALSE;
}
int nLen = sizeof (addrPeer );
PVOID lpSendBuffer = NULL;
DWORD dwSendDataLength = 0;
DWORD dwBytesSent = 0;
// 重点
BOOL bResult = lpConnectEx (ClientSocket ,
(sockaddr *)&addrPeer , // [in] 对方地址
nLen , // [in] 对方地址长度
lpSendBuffer , // [in] 连接后要发送的内容,这里不用
dwSendDataLength , // [in] 发送内容的字节数 ,这里不用
&dwBytesSent , // [out] 发送了多少个字节,这里不用
(OVERLAPPED *)pmyoverlapped ); // [in] 这东西复杂,下一篇有详解
int ret = WSAGetLastError ();
if (!bResult ) // 返回值处理
{
if ( WSAGetLastError () != ERROR_IO_PENDING ) // 调用失败
{
printf (TEXT ("ConnextEx error: %d\n" ),ret);
return FALSE ;
}
else // 操作未决(正在进行中 … )
{
// printf ("WSAGetLastError() == ERROR_IO_PENDING\n" );// 操作正在进行中
}
}