Search code examples
csocketsunix-socket

UNIX Domain Socket programming 3 sockets


I am trying to make a server.c file that supports 3 sockets, which are represented by 3 respective client classes: client1, client2, client3.

In my server.c file, I currently have this code which I found on the internet.

If I wanted to make it have 3 sockets. I want to use the select() command to see the write activities of the 3 clients. My question is how can I use this to support 3 sockets.

Can I bind the 3 clients to 3 sockets that the server can listen to? If so, how can the server listen to these 3 sockets respectively? With an array possibly?

#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>

#define socket1 "sock1"
#define socket2 "sock2"
#define socket3 "sock3"

int main(int argc, char *argv[]) {
    //struct sockaddr_un addr;
    struct sockaddr_un addr1;
    struct sockaddr_un addr2;
    struct sockaddr_un addr3;
    char buf[100];
    int socket1;
    int socket2;
    int socket3;
    //int fd;
    int cl,rc;

    if (argc > 1) socket_path=argv[1];

    if ( (socket1 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        perror("socket error");
        exit(-1);
    }

    memset(&addr1, 0, sizeof(addr1));
    addr1.sun_family = AF_UNIX;
    strncpy(addr1.sun_path, socket_path, sizeof(addr1.sun_path)-1);

    unlink(socket_path1);

    if ( (socket2 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        perror("socket error");
        exit(-1);
    }

    memset(&addr2, 0, sizeof(addr2));
    addr1.sun_family = AF_UNIX;
    strncpy(addr2.sun_path, socket_path, sizeof(addr2.sun_path)-1);

    unlink(socket_path2);

    if ( (socket3 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
        perror("socket error");
        exit(-1);
    }

    memset(&addr3, 0, sizeof(addr3));
    addr3.sun_family = AF_UNIX;
    strncpy(addr3.sun_path, socket_path, sizeof(addr3.sun_path)-1);

    unlink(socket_path3);

    if (bind(socket1, (struct sockaddr*)&addr1, sizeof(addr1)) == -1) {
        perror("bind error");
        exit(-1);
    }

    if (bind(socket2, (struct sockaddr*)&addr2, sizeof(addr2)) == -1) {
        perror("bind error");
        exit(-1);
    }

    if (bind(socket3, (struct sockaddr*)&addr3, sizeof(addr3)) == -1) {
        perror("bind error");
        exit(-1);
    }

    if (listen(socket1, 5) == -1) {
        perror("listen error");
        exit(-1);
    }

    if (listen(socket2, 5) == -1) {
        perror("listen error");
        exit(-1);
    }

    if (listen(socket3, 5) == -1) {
        perror("listen error");
        exit(-1);
    }

    while (1) {
        if ( (cl = accept(fd, NULL, NULL)) == -1) {
            perror("accept error");
            continue;
        }

        while ( (rc=read(cl,buf,sizeof(buf))) > 0) {
            printf("read %u bytes: %.*s\n", rc, rc, buf);
        }
        if (rc == -1) {
            perror("read");
            exit(-1);
        }
        else if (rc == 0) {
            printf("EOF\n");
            close(cl);
        }
    }

    return 0;
}

Solution

  • If you want three listening sockets in the same process, you have to make them unique. In the AF_INET family you do that by bind(2)-ing different ports, in the AF_UNIX family you do that with different paths.

    Also your line:

    char *socket_path = "\0hidden";
    

    has at least two problems:

    • Type of the string literal on the right side of the assignment is const char[8], which decays to const char* pointer type, but not char* type. Make the left hand side const char*. Plus, compile with higher warning level, like -Wall -pedantic to get help from your compiler.
    • Zero byte at the beginning of the string makes strncpy(3) not copy anything, since it copies at most n characters from the string pointed to by src, including the terminating null byte ('\0').

    Create a function that take UNIX path as an argument and creates, binds, and marks socket as listening, and returns created socket descriptor. Call it three times - you have three listening UNIX sockets. Setup select(2) on them for reading - that'll tell you when client connections arrive. At that point call accept(2) on the active socket to get connected client socket, which is separate from the listening socket itself.