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
Post a Comment