winsock - Sockets using GetQueuedCompletionStatus and ERROR_MORE_DATA -


i trying use getqueuedcompletionstatus winsocks, can't seem right. procedure follows:

void foo() {     ...     socket sck = wsasocket(af_inet, sock_dgram, 0,          null, 0, wsa_flag_overlapped);     ....     bind(sck,(struct sockaddr *)&addr,sizeof(struct sockaddr_in));     handle hport = createiocompletionport((handle)sck, null, 0, 0 );     overlapped poverlapped = {0,};     wsarecvfrom(sck,null,0,null,null,(struct sockaddr *)&laddr,&lsize,&poverlapped,0);     bool breturn = getqueuedcompletionstatus(             hport,             &rbytes,             (lpdword)&lpcontext,             &poutoverlapped,             infinite);     ... } 

i send network data bound port external tool. getqueuedcompletionstatus returns false, , getlasterror() returns error_more_data, sounds correct, since hadn't provided buffer in wsarecvfrom.

the question how can provide buffer data failed i/o operation?

i tried issue wsarecvfrom original overlapped structured, queues read, , subsequent call getqueuedcompletionstatus not return until more network data sent.

calling wsarecvfrom without overlapped structure blocks it, , doesn't return until more network data sent.

so, how can handle error_more_data properly, without losing data first operation?

you must provide buffer wsarecvfrom(), read operation regardless of whether use iocp or not. must ensure buffer stays valid in memory until iocp operation complete. iocp fills buffer provide , notifies completion port when finished.

udp cannot transfer more 65535 bytes in single datagram, can use max buffer size.

in example, code written run synchronously (defeating purpose of using iocp @ all), can use local buffer:

void foo() {     ...     socket sck = wsasocket(af_inet, sock_dgram, 0, null, 0, wsa_flag_overlapped);     if (sck == invalid_socket)     {         // error, something...         return;     }     ....     bind(sck,(struct sockaddr *)&addr, sizeof(struct sockaddr_in));     handle hport = createiocompletionport((handle)sck, null, 0, 0 );     if (!hport)     {         // error, something...         return;     }      wsaoverlapped overlapped = {0};     overlapped.hevent = wsacreateevent();      byte buffer[0xffff];     dword dwbytesrecvd = 0;     dword dwflags = 0;     sockaddr_in fromaddr = {0};     int fromaddrlen = sizeof(fromaddr);      wsabuf buf;     buf.len = sizeof(buffer);     buf.buf = buffer;      int iret = wsarecvfrom(sck, &buf, 1, &dwbytesrecvd, &dwflags, (sockaddr*)&fromaddr, &fromaddrlen, &overlapped, null);     if (iret == socket_error)     {         if (wsagetlasterror() != wsa_io_pending)         {            // error, something...            return;         }          dword rbytes;         ulong_ptr key;         lpoverlapped poverlapped = null;          if (!getqueuedcompletionstatus(hport, &rbytes, &key, &poverlapped, infinite))         {             if (poverlapped)             {                 // wsarecvfrom() failed...             }             else             {                 // getqueuedcompletionstatus() failed...             }              // something...             return;         }     }      // i/o complete, use buffer, dwbytesrecvd, dwflags, , fromaddr needed... } 

however, defeats purpose of iocp. if want synchronous, use recvfrom() instead , let block calling thread until data arrives. iocp works best when have pool of threads servicing completion port. call wsarecvfrom() , let work in background, don't wait on it. let separate thread call getqueuedcompletionport() , process data when received, eg:

struct myoverlapped {     wsaoverlapped overlapped;     byte buffer[0xffff];     dword buflen;     dword flags;     sockaddr_storage fromaddr;     int fromaddrlen; };  handle hport = null;  void foo() {     ...     socket sck = wsasocket(af_inet, sock_dgram, 0, null, 0, wsa_flag_overlapped);     if (sck == invalid_socket)     {         // error, something...         return;     }     ....     bind(sck,(struct sockaddr *)&addr, sizeof(struct sockaddr_in));     hport = createiocompletionport((handle)sck, null, 0, 0 );     if (!hport)     {         // error, something...         return;     }      myoverlapped *ov = new myoverlapped;     zeromemory(ov, sizeof(*ov));     ov->overlapped.hevent = wsacreateevent();     ov->fromaddrlen = sizeof(ov->fromaddr);      wsabuf buf;     buf.len = sizeof(ov->buffer);     buf.buf = ov->buffer;      int iret = wsarecvfrom(sck, &buf, 1, &ov->buflen, &ov->flags, (sockaddr*)&ov->fromaddr, &ov->fromaddrlen, (wsaoverlapped*)ov, null);     if (iret == socket_error)     {         if (wsagetlasterror() != wsa_io_pending)         {            // error, something...            return;         }          // wsarecvfrom() operating in background,         // iocp port signaled when finished...     }     else     {         // data available,         // iocp port signaled immediately...     }      ... }  ...  // in thread...  {     ...      dword rbytes;     ulong_ptr key;     myoverlapped *ov = null;      if (!getqueuedcompletionstatus(hport, &rbytes, &key, (lpoverlapped*)&ov, infinite))     {         if (ov)         {             // wsarecvfrom() failed...             // free ov, or reuse operation...         }         else         {             // getqueuedcompletionstatus() failed...         }     }     else     {         // use ov needed...         // free ov, or reuse operation...     }      ... } 

Comments

Popular posts from this blog

yii2 - Yii 2 Running a Cron in the basic template -

asp.net - 'System.Web.HttpContext' does not contain a definition for 'GetOwinContext' Mystery -

mercurial graft feature, can it copy? -