2011-04-19 36 views
6

TCP IOCP istemcisini uygularken bazı sorun yaşıyorum. Mac OSX üzerinde küme gerçekleştirdim, bu yüzden pencereler üzerinde benzer bir şey yapmak istiyordum ve benim anlayışım IOCP'nin en yakın şey olduğudur. Asıl sorun GetCompetetionStatus'un asla geri dönmemesi ve zaman aşımına uğramasıdır. İzlemek için tanıtıcıyı oluştururken bir şeyleri kaçırdığımı, ancak ne olduğundan emin olmadığımı varsayalım. Şimdiye kadar aldık burasıdır:IOCP C++ TCP istemcisi

Benim bağlantı rutin: Burada

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; 

gönderme rutindir (netlik için işleme bazı hata kaldırın):

(aynı zamanda netlik için işleme bazı hata kaldırmak)
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; 

}

Herhangi bir içgörü takdir edilecektir.

+0

Gerçekten "CreateIoCompletionPort" öğesinden dönüş değerini kontrol ediyor musunuz? Her işlevdeki CreateIoCompletionPort öğesinin her ikisini de 87 (yanlış parametre) ve 6 hatası (geçersiz tanıtıcı) döndürdüğünde GetLastError öğesini koyarak –

+0

. Her ikisi de geçerli tanıtıcıları (ServerSocket ve bağlantı noktası) oldukları için neden yanlış döndüklerinden emin değilim. – daltoniam

cevap

5

Aynı soketi birden çok IOCompletionPorts ile ilişkilendiriyorsunuz. Eminim bu geçerli değil. IOPortConnect işlevinizde (yazmayı yaptığınız yerde), bir çekim tutamacında 4 kez geçerek CreateIOCompletionPort'u çağırırsınız.

Benim tavsiyem:

  • tek IOCompletion Limanı (yani, sonuçta, çok sayıda soket ilişkilendirmek) oluşturun.
  • Bir iş parçacığı havuzu oluşturma (CreateThread'i çağırarak), her biri GetQueuedCompletionStatus'u bir döngüde arayarak IOCompletionPort tutamacını engeller.
  • Bir veya daha fazla WSA_OVERLAPPED soket oluşturun ve her birini IOCompletionPort ile ilişkilendirin.
  • Örtüşen işlemleri tetiklemek için OVERLAPPED * alan WSA yuvası işlevlerini kullanın.
  • Çalışan iş parçacığı, GetQueuedCompletionStatus'tan, işlemi başlatmak için ilettiğiniz OVERLAPPED * ile döndüğünde, verilen isteklerin tamamlanmasını işleyin.

Not: WSASend hem 0 döner ve kodları GetQueuedCompletionStatus gelen bir IO Tamamlama Packet alacak belirtmek üzere WSA_IO_PENDING WSAGetLastError ile SOCKET_ERROR(). Başka bir hata kodu, bir IO işlemi kuyruğa alınmadığı için hatayı hemen işlemeniz gerektiği anlamına gelir, böylece başka bir geri arama yapılmayacaktır.

Not2: OVERLAPPED * WSASend'e (veya herhangi bir şeye) verilen işleve GetQueuedCompletionStatus'dan döndürülen OVERLAPPED * iletilir.

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

Teşekkürler.Bunu uygularım ve çalışıp çalışmadığımı göreceğim. Zaman ayırdığın için teşekkürler. – daltoniam

2

Chris sorunların çoğuna değinmiştir ve muhtemelen örnek kod bol baktım ama ...

: Sen çağrısı ile daha bağlam bilgi aktarmak için bu gerçeği kullanabilirsiniz Kullanabileceğiniz bazı ücretsiz IOCP kodum var: http://www.serverframework.com/products---the-free-framework.html

Ayrıca, bu sayfadan bağlantılı konuyla ilgili CodeProject makalelerim de bulunmaktadır.

+0

Bağlantı için teşekkürler Bir göz atacağım. – daltoniam