windows IOCP C++ TCP 客户端

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5717771/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 16:41:10  来源:igfitidea点击:

IOCP C++ TCP client

c++windowstcpiocp

提问by daltoniam

I am having some trouble implementing TCP IOCP client. I have implemented kqueue on Mac OSX so was looking to do something similar on windows and my understanding is that IOCP is the closest thing. The main problem is that GetCompetetionStatus is never returning and always timeouts out. I assume I am missing something when creating the handle to monitor, but not sure what. This is where I have gotten so far:

我在实现 TCP IOCP 客户端时遇到了一些麻烦。我已经在 Mac OSX 上实现了 kqueue,所以希望在 Windows 上做类似的事情,我的理解是 IOCP 是最接近的。主要问题是 GetCompetetionStatus 永远不会返回并且总是超时。我假设我在创建要监控的句柄时遗漏了一些东西,但不确定是什么。这是我到目前为止得到的地方:

My connect routine: (remove some error handling for clarity )

我的连接例程:(为了清楚起见,删除了一些错误处理)

struct sockaddr_in server;
struct hostent *hp;
SOCKET sckfd;
WSADATA wsaData;

int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );


if ((hp = gethostbyname(host)) == NULL)
    return NULL;
WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED)
if ((sckfd = WSASocket(AF_INET,SOCK_STREAM,0, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
    printf("Error at socket(): Socket\n");
    WSACleanup();
    return NULL;
}

server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr = *((struct in_addr *)hp->h_addr);
memset(&(server.sin_zero), 0, 8);

//non zero means non blocking. 0 is blocking.
u_long iMode = -1;
iResult = ioctlsocket(sckfd, FIONBIO, &iMode);
if (iResult != NO_ERROR)
    printf("ioctlsocket failed with error: %ld\n", iResult);


HANDLE hNewIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, ulKey, 0);
CreateIoCompletionPort((HANDLE)sckfd, hNewIOCP , ulKey, 0);

connect(sckfd, (struct sockaddr *)&server, sizeof(struct sockaddr));

//WSAConnect(sckfd, (struct sockaddr *)&server, sizeof(struct sockaddr),NULL,NULL,NULL,NULL);

return sckfd;   

Here is the send routine: ( also remove some error handling for clarity )

这是发送例程:(为了清楚起见,还删除了一些错误处理)

IOPortConnect(int ServerSocket,int timeout,string& data){

char buf[BUFSIZE];
strcpy(buf,data.c_str());
WSABUF buffer = { BUFSIZE,buf };
DWORD bytes_recvd;
int r;
ULONG_PTR ulKey = 0;
OVERLAPPED overlapped;
 OVERLAPPED* pov = NULL;
HANDLE port;

HANDLE hNewIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, ulKey, 0);
CreateIoCompletionPort((HANDLE)ServerSocket, hNewIOCP , ulKey, 0);


BOOL get = GetQueuedCompletionStatus(hNewIOCP,&bytes_recvd,&ulKey,&pov,timeout*1000);

if(!get)
    printf("waiton server failed. Error: %d\n",WSAGetLastError());
if(!pov)
    printf("waiton server failed. Error: %d\n",WSAGetLastError());

port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (u_long)0, 0);

SecureZeroMemory((PVOID) & overlapped, sizeof (WSAOVERLAPPED));

r = WSASend(ServerSocket, &buffer, 1, &bytes_recvd, NULL, &overlapped, NULL);
printf("WSA returned: %d WSALastError: %d\n",r,WSAGetLastError());
if(r != 0)
{
    printf("WSASend failed %d\n",GetLastError());
    printf("Bytes transfered: %d\n",bytes_recvd);
}
if (WSAGetLastError() == WSA_IO_PENDING)
    printf("we are async.\n");
CreateIoCompletionPort(port, &overlapped.hEvent,ulKey, 0);

BOOL test = GetQueuedCompletionStatus(port,&bytes_recvd,&ulKey,&pov,timeout*1000); 

CloseHandle(port);
return true;

}

}

Any insight would be appreciated.

任何见解将不胜感激。

采纳答案by Chris Becke

You are associating the same socket with multiple IOCompletionPorts. I'm sure thats not valid. In your IOPortConnect function (Where you do the write) you call CreateIOCompletionPort 4 times passing in one shot handles.

您将同一个套接字与多个 IOCompletionPort 相关联。我确定那是无效的。在您的 IOPortConnect 函数(您在何处进行写入)中,您调用 CreateIOCompletionPort 4 次,传入一次处理。

My advice:

我的建议:

  • Create a single IOCompletion Port (that, ultimately, you associate numerous sockets with).
  • Create a pool of worker threads (by calling CreateThread) that each then block on the IOCompletionPort handle by calling GetQueuedCompletionStatus in a loop.
  • Create one or more WSA_OVERLAPPED sockets, and associate each one with the IOCompletionPort.
  • Use the WSA socket functions that take an OVERLAPPED* to trigger overlapped operations.
  • Process the completion of the issued requests as the worker threads return from GetQueuedCompletionStatus with the OVERLAPPED* you passed in to start the operation.
  • 创建单个 IOCompletion 端口(最终,您将多个套接字与之关联)。
  • 创建一个工作线程池(通过调用 CreateThread),然后每个线程通过在循环中调用 GetQueuedCompletionStatus 来阻塞 IOCompletionPort 句柄。
  • 创建一个或多个 WSA_OVERLAPPED 套接字,并将每个套接字与 IOCompletionPort 相关联。
  • 使用采用 OVERLAPPED* 的 WSA 套接字函数来触发重叠操作。
  • 在工作线程从 GetQueuedCompletionStatus 返回时处理已发出请求的完成,并使用您传入的 OVERLAPPED* 来启动操作。

Note: WSASend returns both 0, and SOCKET_ERROR with WSAGetLastError() as WSA_IO_PENDING as codes to indicate that you will get an IO Completion Packet arriving at GetQueuedCompletionStatus. Any other error code means you should process the error immediately as an IO operation was not queued so there will be no further callbacks.

注意:WSASend 返回 0 和 SOCKET_ERROR,WSAGetLastError() 作为 WSA_IO_PENDING 作为代码,表明您将收到一个到达 GetQueuedCompletionStatus 的 IO 完成数据包。任何其他错误代码意味着您应该立即处理错误,因为 IO 操作未排队,因此不会有进一步的回调。

Note2: The OVERLAPPED* passed to the WSASend (or whatever) function is the OVERLAPPED* returned from GetQueuedCompletionStatus. You can use this fact to pass more context information with the call:

注 2:传递给 WSASend(或其他)函数的 OVERLAPPED* 是从 GetQueuedCompletionStatus 返回的 OVERLAPPED*。您可以使用此事实通过调用传递更多上下文信息:

struct MYOVERLAPPED {
  OVERLAPPED ovl;
};
MYOVERLAPPED ctx;
WSASend(...,&ctx.ovl);
...
OVERLAPPED* pov;
if(GetQueuedCompletionStatus(...,&pov,...)){
  MYOVERLAPPED* pCtx = (MYOVERLAPPED*)pov;

回答by Len Holgate

Chris has dealt with most of the issues and you've probably already looked at plenty of example code, but...

Chris 已经处理了大部分问题,您可能已经看过大量示例代码,但是……

I've got some free IOCP code that's available here: http://www.serverframework.com/products---the-free-framework.html

我有一些免费的 IOCP 代码可以在这里找到:http: //www.serverframework.com/products---the-free-framework.html

There are also several of my CodeProject articles on the subject linked from that page.

还有我的几篇关于该主题的 CodeProject 文章从该页面链接。