www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Socket.send

reply Andrea Fontana <advmail katamail.com> writes:
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)?
Sep 26 2011
parent reply mta`chrono <chrono mta-international.net> writes:
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.
Sep 26 2011
parent reply Andrea Fontana <advmail katamail.com> writes:
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?
Sep 26 2011
parent reply "Regan Heath" <regan netmail.co.nz> writes:
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/
Sep 27 2011
next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
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/
Sep 27 2011
prev sibling parent reply Andrea Fontana <advmail katamail.com> writes:
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?
Sep 27 2011
parent "Regan Heath" <regan netmail.co.nz> writes:
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/
Sep 27 2011