Thread overview
How to cleanup after Socket.bind on Linux?
Aug 27, 2013
Ali Çehreli
Aug 27, 2013
dnewbie
Aug 27, 2013
Regan Heath
Aug 28, 2013
Ali Çehreli
August 27, 2013
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
August 27, 2013
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.
August 27, 2013
On Tue, 27 Aug 2013 04:30:10 +0100, Ali Çehreli <acehreli@yahoo.com> wrote:
> 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 not 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 Windows 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/
August 28, 2013
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