user4592590
user4592590

Reputation:

How to make sure that WSASend() will send the data?

WSASend() will return immediately whether the data will be sent or not. But how to make sure that data will be sent, for example I have a button in my UI that will send "Hello World!" when pressed. Now I want to make sure that when the user click on this button the "Hello World!" will be sent at some point, but WSASend() could return WSAEWOULDBLOCK indicating that data will not be sent, so should I enclose WSASend() in a loop that does not exit until WSASend() returns 0 (success).

Note: I am using IOCP.

Upvotes: 2

Views: 4018

Answers (2)

hlscalon
hlscalon

Reputation: 7552

Overlapped Socket I/O

If an overlapped operation completes immediately, WSASend returns a value of zero and the lpNumberOfBytesSent parameter is updated with the number of bytes sent. If the overlapped operation is successfully initiated and will complete later, WSASend returns SOCKET_ERROR and indicates error code WSA_IO_PENDING.

...

The error code WSA_IO_PENDING indicates that the overlapped operation has been successfully initiated and that completion will be indicated at a later time. Any other error code indicates that the overlapped operation was not successfully initiated and no completion indication will occur.

...

So as demonstrated in docs, you don't need to enclose in a loop, just check for a SOCKET_ERROR and if the last error is not equal to WSA_IO_PENDING, everything is fine:

rc = WSASend(AcceptSocket, &DataBuf, 1,
             &SendBytes, 0, &SendOverlapped, NULL);
if ((rc == SOCKET_ERROR) &&
    (WSA_IO_PENDING != (err = WSAGetLastError()))) {
    printf("WSASend failed with error: %d\n", err);
    break;
}

Upvotes: 1

Martin James
Martin James

Reputation: 24857

should I enclose WSASend() in a loop that does not exit until WSASend() returns 0 (success)

Err.. NO!

Have the UI issue an overlapped WSASend request, complete with buffer/s and OVERLAPPED/s. If, by some miracle, it does actually return success immedately, (and I've never seen it), you're good.

If, (when:), it returns WSA_IO_PENDING, you can do nothing in your UI button-handler because GUI event-handlers cannot wait. Graphical UI's are state-machines - you must exit the button-handler and return to the message input queue in prompt manner. You can do some GUI stuff, if you want. Maybe disable the 'Send' button, or add some 'Message sent' text to a memo component. That's about it - you must then exit.

Some time later, the successful completion notification, (or failure notification), will get posted to the IOCP completion queue and a handler thread will get hold of it. Use PostMessage, QueueUserAPC or similar inter-thread comms mechanism to signal 'something', (eg. the buffer object used in the original WSASend), back to the UI thread so that it can take action/s on the returned result, eg. re-enabling the 'Send' button.

Yes, it can be seen as messy, but it is the only way you can do it that will work well.

Other approaches - polling loops, Application.DoEvents, timers etc are all horrible bodges.

Upvotes: 3

Related Questions