www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to cleanup after Socket.bind on Linux?

reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
The following simple socket example is trying to cleanup after itself, 
except the bind() call. As I repeat in the QUESTION comment below, I 
have read the man page of bind and I know that I need to unlink a path. 
How can I get that path?

The program waits on localhost:8080, receives N number of data and 
responds with "Hello World!".

The problem is, currently the program apparently leakes some resources. 
It cannot be started a second time for 8080 still being in use, unless 
you wait for several seconds, presumably until the OS does the cleanup.

import std.stdio;
import std.socket;
import std.string;

enum port = 8080;

void main()
{
     server();
}

void server()
{
     // Prepare the socket
     auto listener = new TcpSocket();
     scope (exit) {
         writefln("Shutting down and closing the listener");
         listener.shutdown(SocketShutdown.BOTH);
         listener.close();
     }

     /*
      * The port to listen to
      *
      * Note that the following perhaps naive code does not work on OSX. Try
      * the following line instead:
      *
      *   listener.bind(new InternetAddress(port));
      */
     Address[] addresses = getAddress("localhost", port);
     writefln("Addresses: %s", addresses);
     auto address = addresses[0];
     writefln("Address: %s", address);
     listener.bind(address);
     scope (exit) {
         /*
          * QUESTION: What to do here?
          *
          * According to 'man bind', the path that represents the 
address must
          * be unlink'ed. However, the path seems to be available only 
through
          * UnixAddress.path but UnixAddress is not available by default 
and it
          * is not convenient to use (e.g. it does not have a 
constructor that
          * takes the port value).
          */
     }

     // Wait for the client
     listener.listen(1);
     writeln("Waiting for the client");

     // Accept the connection
     Socket connection = listener.accept();
     scope (exit) {
         writefln("Shutting down and closing the client connection %s",
                  connection.remoteAddress());
         connection.shutdown(SocketShutdown.BOTH);
         connection.close();
     }

     ubyte[1000] buffer;
     bool isAllReceived = false;

     while (!isAllReceived) {
         const received = connection.receive(buffer);

         if (received == Socket.ERROR) {
             writeln("READ ERROR");
             break;

         } else {
             writefln("Received %s bytes; as string: %s",
                      received, cast(string)buffer[0..received]);
         }

         isAllReceived = (received < buffer.length);
     }

     if (isAllReceived) {
         enum header =
             "HTTP/1.0 200 OK\nContent-Type: text/html; charset=utf-8\n\n";

         string response = header ~ "Hello World!\n";
         connection.send(response);
     }
}

Thank you,
Ali
Aug 26 2013
next sibling parent "dnewbie" <run3 myopera.com> writes:
On Tuesday, 27 August 2013 at 03:30:11 UTC, Ali Çehreli wrote:
 It cannot be started a second time for 8080 still being in use, 
 unless you wait for several seconds
It works on Windows7, no need to wait.
Aug 26 2013
prev sibling parent reply "Regan Heath" <regan netmail.co.nz> writes:
On Tue, 27 Aug 2013 04:30:10 +0100, Ali =C7ehreli <acehreli yahoo.com> w=
rote:
 The following simple socket example is trying to cleanup after itself,=
=
 except the bind() call. As I repeat in the QUESTION comment below, I  =
 have read the man page of bind and I know that I need to unlink a path=
. =
 How can I get that path?
That example is for AF_UNIX domain sockets. TcpSocket is an AF_INET = domain socket. In AF_INET there is no 'path' and there is nothing you = need to do to cleanup after bind - other than close the socket. I do no= t = believe a shutdown is required for a listening socket - tho don't quote = me = on that.
 The problem is, currently the program apparently leakes some resources=
. =
 It cannot be started a second time for 8080 still being in use, unless=
=
 you wait for several seconds, presumably until the OS does the cleanup=
. Correct. And this time varies by platform, as dnewbie mentions on Windo= ws = you can re-use immediately. You could set the REUSE option on the socket prior to 'bind', this would= = allow you to bind again while the previous socket was in cleanup. The other thing which might be affecting things is.. Take a look at: http://linux.die.net/man/7/socket Specifically "SO_LINGER". This socket option controls whether and how = long a socket will linger after it is closed. I am not sure what the = linux defaults are for that, but it may be set to linger intentionally. = = You could use getsockopt to obtain the LINGER default values and see. Also.. the sentence "When the socket is closed as part of exit(2), it = always lingers in the background." made me think, when does scope(exit) = = fire? Does it occur as part of exit in your example? Does manually = calling shutdown/close on the listening socket resolve the issue. Regan -- = Using Opera's revolutionary email client: http://www.opera.com/mail/
Aug 27 2013
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/27/2013 02:02 AM, Regan Heath wrote:

 You could set the REUSE option on the socket prior to 'bind', this would
 allow you to bind again while the previous socket was in cleanup.
That worked. I copied the following line from std/socket.d: listener.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true); Ali
Aug 27 2013