Search code examples
dunix-socket

How to do IPC using Unix Domain Socket in D?


Here I have a program that wants to

  1. detect whether if it's the only instance

    1.1. it does that by trying to create a Unix Domain Socket and trying to binding it to a specific address.

  2. if a duplicate program is not running, establish an UDS and then listen to the socket.

    2.1. if any message comes through that socket, the program will log the incoming message

    2.2. otherwise it should keep listening to the socket forever

  3. if there's a duplicate program it should send a message and then exit.

Here's what I have:

import std.socket, std.experimental.logger;

immutable string socketAddress = "\0/tmp/com.localserver.myapp";

void main()
{
    auto socket = new std.socket.Socket(std.socket.AddressFamily.UNIX,
            std.socket.SocketType.STREAM);
    auto addr = new std.socket.UnixAddress(socketAddress);

    auto isUnique = () {
        bool result;

        scope (success)
            log("returns: ", result);

        try
        {
            socket.bind(addr);
            result = true;
        }
        catch (std.socket.SocketOSException e)
            result = false;

        // else throw error
        return result;
    }();

    if (isUnique)
    {
        log("Unique instance detected. Listening...");
        // works upto now
        char[] buffer = [];
        while (1)
        {
            socket.listen(0);
            socket.receive(buffer);
            if (buffer != []) {
                log("Received message: ", buffer);
            }
            buffer = [];
        }
    }
    else
    {
        log("Duplicate instance detected.");
        socket.connect(addr);
        import std.stdio;
        stdout.write("Enter your message:\t");
        socket.send(readln());
        log("Message has been sent. Exiting.");
    }
}

The documentation does not seem very friendly to those who does not have any experience in socket programming. How can I send and receive message with std.socket.Socket?


Solution

  • After binding, you actually need to accept. It will return a new Socket instance which you can actually receive from. Your client side branch looks ok. I think that is your key mistake here.

    I also have a code sample in my book that shows basic functionality of std.socket which can help as an example: http://arsdnet.net/dcode/book/chapter_02/03/

    it is tcp, but making it unix just means changing the family, like you already did in your code.

    You can also look up socket tutorials for C and so on, the D socket is just a thin wrapper around those same BSD style socket functions.