简体   繁体   English

IOCP C ++ TCP客户端

[英]IOCP C++ TCP client

I am having some trouble implementing TCP IOCP client. 我在实施TCP IOCP客户端时遇到了一些麻烦。 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. 我已经在Mac OSX上实现了kqueue,所以我希望在Windows上做类似的事情,我的理解是IOCP是最接近的东西。 The main problem is that GetCompetetionStatus is never returning and always timeouts out. 主要问题是GetCompetetionStatus永远不会返回并且总是超时。 I assume I am missing something when creating the handle to monitor, but not sure what. 我假设我在创建要监控的句柄时遗漏了一些东西,但不确定是什么。 This is where I have gotten so far: 这是我到目前为止的地方:

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. 任何见解将不胜感激。

You are associating the same socket with multiple IOCompletionPorts. 您正在将同一套接字与多个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. 在您的IOPortConnect函数(写入的位置)中,调用CreateIOCompletionPort 4次传递一次性句柄。

My advice: 我的建议:

  • Create a single IOCompletion Port (that, ultimately, you associate numerous sockets with). 创建一个IOCompletion端口(最终,您将多个套接字关联起来)。
  • Create a pool of worker threads (by calling CreateThread) that each then block on the IOCompletionPort handle by calling GetQueuedCompletionStatus in a loop. 创建一个工作线程池(通过调用CreateThread),然后通过在循环中调用GetQueuedCompletionStatus来阻塞IOCompletionPort句柄。
  • Create one or more WSA_OVERLAPPED sockets, and associate each one with the IOCompletionPort. 创建一个或多个WSA_OVERLAPPED套接字,并将每个套接字与IOCompletionPort相关联。
  • Use the WSA socket functions that take an OVERLAPPED* to trigger overlapped operations. 使用带有OVERLAPPED *的WSA套接字函数来触发重叠操作。
  • Process the completion of the issued requests as the worker threads return from GetQueuedCompletionStatus with the OVERLAPPED* you passed in to start the operation. 当工作线程从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. 注意:WSASend返回0和SOCKET_ERROR,WSAGetLastError()为WSA_IO_PENDING作为代码,表示您将获得到达GetQueuedCompletionStatus的IO完成数据包。 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. 任何其他错误代码意味着您应该立即处理错误,因为IO操作没有排队,因此不会再有回调。

Note2: The OVERLAPPED* passed to the WSASend (or whatever) function is the OVERLAPPED* returned from GetQueuedCompletionStatus. 注意2:传递给WSASend(或其他)函数的OVERLAPPED *是从GetQueuedCompletionStatus返回的OVERLAPPED *。 You can use this fact to pass more context information with the call: 您可以使用此事实通过调用传递更多上下文信息:

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

Chris has dealt with most of the issues and you've probably already looked at plenty of example code, but... 克里斯已经处理了大部分问题,你可能已经看过很多示例代码,但......

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文章与该页面相关联。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM