简体   繁体   中英

Socket Send/receive simultaneously

can any one point out the reason why u cant send and receive on a socket at the same time ?

to my understanding there are 2 streams one to push and one to pull

if you attempt to send/receive simultaneously you will get wasealready error

what is the reason that the socket throws wasealready error (10035) does it have any thing to do with the ack window the receiving side sends back ? as if to keep the line open for the window ?

First, I think you're confused with your error codes. Here's a few codes that might be relevant:

  • WSAEALREADY (10037) - You attempt to issue a request that's already in progress. Eg, trying to connect() with a socket that's already in the middle of connecting.
  • WSAEINPROGRESS (10036) - You attempt to issue more than one blocking operation at once, even across multiple threads.
  • WSAEWOULDBLOCK (10035) - You attempt to make a call that would have blocked (eg, recv when there's no data available) when the socket is in non-blocking mode.

The main factor preventing you from doing two blocking operations at once is the WSAEINPROGRESS error - a limitation in the Winsock 1.1 API only allows you to do one blocking operation at once. You can get around this by using non-blocking overlapped calls and the Winsock 2.0 API to simulate blocking calls. For example:

SOCKET sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
WSAEVENT hEvent = WSACreateEvent();
WSAEventSelect(sock, hEvent, FD_CONNECT); // register for connect notification
long iMode=1;
ioctlsocket(sock,FIONBIO,&iMode); // set non-blocking mode

WSAConnect(sock, address, sizeof(address), NULL, NULL, NULL, NULL);
WSAWaitForMultipleEvents(1, &events, FALSE, INFINITE, FALSE);

WSANETWORKEVENTS connect_result;
WSAEnumNetworkEvents(sock, hEvent, &connect_result);
if (connect_result.iErrorCode[FD_CONNECT] != 0) {
  // connect failed, do something about it
}
WSACloseEvent(hEvent);

iMode = 0;
ioctlsocket(sock,FIONBIO,&iMode); // clear non-blocking mode; it won't play well with overlapped IO below

// Start an overlapped send
char *my_data = "Hello, world!";
WSAOVERLAPPED send_overlapped;
WSABUF send_buf;
send_buf.len = strlen(my_data);
send_buf.buf = my_data;
send_overlapped.hEvent = WSACreateEvent();
DWORD bytesSent;
WSASend(sock, &send_buf, 1, &bytesSent, 0, &send_overlapped, NULL);
if (WSAGetLastError() != WSA_IO_PENDING) {
    // something went wrong, handle the error...
}


// Start an overlapped receive
char rdata[256];
WSAOVERLAPPED recv_overlapped;
WSABUF recv_buf;
recv_buf.len = sizeof(rdata);
recv_buf.buf = rdata;
recv_overlapped.hEvent = WSACreateEvent();
DWORD bytesRecvd;
WSARecv(sock, &recv_buf, 1, &bytesRecvd, NULL, &recv_overlapped, NULL);
if (WSAGetLastError() != WSA_IO_PENDING) {
    // something went wrong, handle the error...
}

// Now wait for both to finish
WSAEVENT events[2];
events[0] = recv_buf.hEvent;
events[1] = send_buf.hEvent;
WSAWaitForMultipleEvents(2, events, TRUE, INFINITE, TRUE);

This approach is a bit more complex, but very flexible - once you fire off an overlapped I/O job, the very same thread can go on to do other work (as long as you keep the buffers and what not allocated!). The one thing to watch out for is that if you do this on your GUI thread, you'll need to change the message loop - in order for overlapped events to complete, the thread that issued them needs to perform an alertable wait using eg MsgWaitForMultipleEvents . In the above example I'm using WSAWaitForMultipleEvents to perform this alertable wait. Also, the thread that issues an overlapped I/O request must not terminate until the request completes.

For more general information on overlapped I/O, see this MSDN page: http://msdn.microsoft.com/en-us/library/ms686358(v=vs.85).aspx

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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