Thread overview
Socket.send
Sep 26, 2011
Andrea Fontana
Sep 26, 2011
mta`chrono
Sep 27, 2011
Andrea Fontana
Sep 27, 2011
Regan Heath
Sep 27, 2011
Regan Heath
Sep 27, 2011
Andrea Fontana
Sep 27, 2011
Regan Heath
September 26, 2011
I'm working on a simple server written in d. I use a SocketSet to check requests from clients.

I have to send back response and close connection. Is there a method to check if socket sent data or not with an async socket (so i can close it)?
September 26, 2011
Am 26.09.2011 18:09, schrieb Andrea Fontana:
> I'm working on a simple server written in d. I use a SocketSet to check requests from clients.
> 
> I have to send back response and close connection. Is there a method to check if socket sent data or not with an async socket (so i can close it)?

Simply use SocketSet and do some kind of select. You'll read 0 bytes from it, if it has disconnected.
September 27, 2011
I'll try to explain it better.

if i write:

socket.send(...);
socket.close();
socket = null;

and send is async, i guess sending will not work properly in this way.

How do i know if send() is still sending or not?
September 27, 2011
On Tue, 27 Sep 2011 01:40:49 +0100, Andrea Fontana <advmail@katamail.com> wrote:

> I'll try to explain it better.
>
> if i write:
>
> socket.send(...);
> socket.close();
> socket = null;
>
> and send is async, i guess sending will not work properly in this way.
>
> How do i know if send() is still sending or not?

I am not sure of the D socket API, but here is how you do it with the underlying BSD sockets API..

The recommended 'graceful' way to close sockets is to use shutdown(SEND) and then wait on recv/select until the remote end has read all the data and signalled shutdown back, for example..

[endpoint-1] .. wants to send and close:

  send(s..);                // send last response
  .. read any expected replies..
  shutdown(s, SD_SEND);     // tell the other end you will send no more data
  .. call recv, if != 0; check for WSAEWOULDBLOCK/EWOULDBLOCK, call select, loop until recv returns 0 ..
  close(s);                 // close


[endpoint-2] .. will react to this in the following way:

  some_loop()
  {
    bytes = recv(s..);      // reading data..
    if(bytes == 0) break;   // no more data
    else if(bytes == SOCKET_ERROR) .. call select, loop ..
    ..etc..
  }
  shutdown(s, SD_SEND);     // tell the other end you will send no more data
  .. call recv, if != 0; check for WSAEWOULDBLOCK/EWOULDBLOCK, call select, loop until recv returns 0 ..
  close(s);                 // close

So.. recv returns 0 if the other calls shutdown(SD_SEND) or close(), so even if endpoint-2 is badly behaved and just calls close you will notice - you just might get a "connection reset" error.  With non blocking sockets recv returns immediately with SOCKET_ERROR (-1) if there is no data, and the "last error" will be EWOULDBLOCK, in which case you can sleep or select and retry the recv until you get a return of 0, meaning socket closed.

If you don't do this, and call close too soon the remote end will get a 'connection reset by peer' error, due to the locally buffered (unsent) data.

R

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/
September 27, 2011
On Tue, 27 Sep 2011 10:53:13 +0100, Regan Heath <regan@netmail.co.nz> wrote:
>    .. call recv, if != 0; check for WSAEWOULDBLOCK/EWOULDBLOCK, call  select, loop until recv returns 0 ..

In this loop you will also need to check for WSAECONNRESET/ECONNRESET to detect a badly behaved remote end calling close without shutdown/recv itself.  You can either chose to swallow/ignore this error, or to log/trace it, whatever is suitable to your application.  I would not recommend throwing an exception or treating it like a failure .. unless you control the code on both ends of the connection as it might indicate a bug in your code.

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/
September 27, 2011
It's a small server (http) so I don't wait for any reply from the client. If there's an header "connection: close", server should close connection when data is sent.

So on server side i should write:

if (httpRequest.isCompleted)
{
   // Parsing request headers
   [... omitted ...]
   // Build http reply
   [... omitted ...]

   socket.send(reply);
   socket.shutdown(SocketShutdown.BOTH);
}


and then wait for client to close connection?

September 27, 2011
On Tue, 27 Sep 2011 11:20:32 +0100, Andrea Fontana <advmail@katamail.com> wrote:

> It's a small server (http) so I don't wait for any reply from the
> client. If there's an header "connection: close", server should
> close connection when data is sent.
>
> So on server side i should write:
>
> if (httpRequest.isCompleted)
> {
>    // Parsing request headers
>    [... omitted ...]
>    // Build http reply
>    [... omitted ...]
>
>    socket.send(reply);
>    socket.shutdown(SocketShutdown.BOTH);
> }
>
>
> and then wait for client to close connection?

Almost.  If the client sends additional data which you do not read above, then shutdown(BOTH) may cause a "connection aborted" error on the client end.  Ideally you want to shutdown(SEND) only, then loop reading all remaining data from the socket (until receive returns 0), then call close().

I've just looked at std.socket and I can't see a nice easy way to call select on just the one/current socket.. I was expecting socket.select(READ|WRITE|EXCEPT) helper functions or similar :(

R

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/