6

TCPIOCPクライアントの実装に問題があります。私はMacOSXにkqueueを実装したので、Windowsでも同様のことをしようとしていましたが、IOCPが最も近いと理解しています。主な問題は、GetCompetetionStatusが返されることはなく、常にタイムアウトになることです。監視するハンドルを作成するときに何かが足りないと思いますが、何がわからないのです。これは私がこれまでに得たところです:

私の接続ルーチン:(明確にするためにいくつかのエラー処理を削除してください)

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;   

送信ルーチンは次のとおりです:(わかりやすくするためにエラー処理も削除してください)

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;

}

任意の洞察をいただければ幸いです。

4

2 に答える 2

5

同じソケットを複数の IOCompletionPorts に関連付けています。それは有効ではないと確信しています。IOPortConnect 関数 (書き込みを行う場所) で、CreateIOCompletionPort を 4 回呼び出して、ワンショット ハンドルを渡します。

私のアドバイス:

  • 単一の IOCompletion ポートを作成します (最終的には、多数のソケットを関連付けます)。
  • (CreateThread を呼び出して) ワーカー スレッドのプールを作成し、ループ内で GetQueuedCompletionStatus を呼び出して、それぞれが IOCompletionPort ハンドルでブロックします。
  • 1 つ以上の WSA_OVERLAPPED ソケットを作成し、それぞれを IOCompletionPort に関連付けます。
  • OVERLAPPED* を受け取る WSA ソケット関数を使用して、重複した操作をトリガーします。
  • 操作を開始するために渡した OVERLAPPED* を使用してワーカー スレッドが GetQueuedCompletionStatus から戻るときに、発行された要求の完了を処理します。

注: WSASend は、GetQueuedCompletionStatus に到着する IO 完了パケットを取得することを示すコードとして、WSAGetLastError() を WSA_IO_PENDING として 0 と SOCKET_ERROR の両方を返します。その他のエラー コードは、IO 操作がキューに入れられていないため、すぐにエラーを処理する必要があることを意味し、それ以上のコールバックはありません。

注 2: WSASend (またはその他) 関数に渡される OVERLAPPED* は、GetQueuedCompletionStatus から返される OVERLAPPED* です。この事実を使用して、呼び出しでより多くのコンテキスト情報を渡すことができます。

struct MYOVERLAPPED {
  OVERLAPPED ovl;
};
MYOVERLAPPED ctx;
WSASend(...,&ctx.ovl);
...
OVERLAPPED* pov;
if(GetQueuedCompletionStatus(...,&pov,...)){
  MYOVERLAPPED* pCtx = (MYOVERLAPPED*)pov;
于 2011-04-19T16:07:29.893 に答える
1

Chris はほとんどの問題に対処しており、おそらく既に多くのサンプル コードを見たことがあるでしょうが...

ここで入手できる無料の IOCP コードを入手しました: http://www.serverframework.com/products---the-free-framework.html

そのページからリンクされた主題に関する私の CodeProject 記事もいくつかあります。

于 2011-04-19T21:00:09.180 に答える