admin管理员组

文章数量:1379618

I have my client-side code like this where the constant SOCKET_PATH is "/tmp/my_socket":

#define SOCKET_PATH "/tmp/my_socket"
//rest of the code

int main(int argc, char *argv[])
{
    struct sockaddr_un server_addr;

    server_addr.sun_family = AF_LOCAL; /*socket locali*/
    strcpy(server_addr.sun_path, SOCKET_PATH);

    if ((socket_fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0)
    {
        perror("Errore creazione welcoming socket");
        return 1;
    }

    if ((connect(socket_fd,
                 (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0))
    {
        perror("Errore connect");
        return 1;
    }

    clientActions();

    /*Pulizia prima della terminazione*/
    close(socket_fd);
    return 0;
}

My server-side is like this:

#define SOCKET_PATH "/tmp/my_socket"
//rest of the code

int main(int argc, char* argv[]) {
    int socket_fd, conn_fd;
    struct sockaddr_un server_addr, client_addr;

    server_addr.sun_family=AF_LOCAL; /*socket locali*/
    unlink(SOCKET_PATH); /*Rimuove la socket se già esiste*/

    strcpy(server_addr.sun_path, SOCKET_PATH);

    printf("Server in esecuzione...\n");
    sleep(1);

    if ((socket_fd=socket(PF_LOCAL,SOCK_STREAM,0)) < 0){
        perror("Errore creazione welcoming socket");
        return 1;
    }
    
    if ((bind(socket_fd,
    (struct sockaddr*)&server_addr,sizeof(server_addr))<0)) {
        perror("Errore bind strano");
        return 1;
    }

    if ((listen(socket_fd, 5)) < 0){ /*5 è la dim della coda di attesa*/
        perror("Errore nel listen");
        return 1;
    }

    while (1) {
        if ((conn_fd = accept(socket_fd,NULL,NULL)) < 0) {
            perror("Errore accept");
            return 1;
        }
        addClientToList(conn_fd);
        pthread_t tid;
        int* conn_fd_ptr = malloc(sizeof(int));
        *conn_fd_ptr = conn_fd; //Per evitare problemi con var condivise
        // TODO: gestione thread
        if (pthread_create(&tid, NULL, connection_handler, conn_fd_ptr) != 0) {
            perror("Errore creazione thread");
            free(conn_fd_ptr);
            close(conn_fd);
            removeClientFromList(conn_fd);
            continue;
        }

        pthread_detach(tid);
    }

    /*Pulizia prima della terminazione*/
    close(socket_fd);
    unlink(SOCKET_PATH);
    return 0;
}

Executing the code without docker using gcc compiler on my Ubuntu Virtual Machine works fine. But when I have to use docker compose something goes wrong about the server side binding. This is the Dockerfile.server:

FROM gcc:11.4

# Crea una cartella per l'app
RUN mkdir -p /opt/app
WORKDIR /opt/app

# Copia i file del server
COPY server.c /opt/app

# Compila il server e collega la libreria pthread
RUN gcc -o server.out server.c -lpthread

# EXPOSE 9200

CMD ["./server.out"]

This is the Dockerfile.client:

FROM gcc:11.4

# Crea una cartella per l'app
RUN mkdir -p /opt/app
WORKDIR /opt/app

# Copia i file del client
COPY client.c /opt/app

# Compila il client e collega la libreria pthread
RUN gcc -o client.out client.c -lpthread

CMD ["./client.out"]

And finally my docker compose is this:

version: '3'
services:
  server:
    build:
      context: .
      dockerfile: Dockerfile.server
    container_name: my_server
    # ports:
    #   - "9000:9100"  # Espone la porta del server sulla macchina host
    volumes:
      - /tmp/my_socket:/tmp/my_socket  # Condivide il socket file

  client:
    build:
      context: .
      dockerfile: Dockerfile.client
    container_name: my_client
    depends_on:
      - server  # Il client parte solo dopo che il server è pronto
    volumes:
      - /tmp/my_socket:/tmp/my_socket  # Usa lo stesso socket file

The error that docker gives me when I'm trying to do docker compose up --build is like this:

[+] Running 3/3
 ✔ Network progettotrislso_default  Created                                                                          0.1s 
 ✔ Container my_server              Created                                                                          0.2s 
 ✔ Container my_client              Created                                                                          0.3s 
Attaching to my_client, my_server
my_client  | Errore connect: Connection refused
my_client exited with code 1
my_server  | Server in esecuzione...
my_server  | Errore bind strano: Address already in use
my_server exited with code 1

I can understand the client error, but why the server error? On my ubuntu it works just fine, what is happening? Does that have to do with the docker volumes?

EDIT

So I've tried to use named volumes as suggested and now my docker compose file looks like this:

    version: '3'

volumes:
  socket:  # Definiamo un volume nominato

services:
  server:
    build:
      context: .
      dockerfile: Dockerfile.server
    container_name: my_server
    # ports:
    #   - "9000:9100"  # Espone la porta del server sulla macchina host
    volumes:
      - socket:/tmp # Condivide il socket file

  client:
    build:
      context: .
      dockerfile: Dockerfile.client
    container_name: my_client
    depends_on:
      - server  # Il client parte solo dopo che il server è pronto
    volumes:
      - socket:/tmp  # Usa lo stesso socket file

When I run docker compose --build now there is no more bind error, however the output now is like this:

[+] Running 2/2

✔ Container my_client Recreated 11.5s ✔ Container my_server Recreated 11.1s Attaching to my_client, my_server

my_client | Benvenuto! Cosa vuoi fare? Premi: //This is my menu

my_client | 1 Per unirti a una partita

my_client | 2 Per creare una partita

my_client | Qualsiasi altro tasto per uscire

my_client | Connessione con il server interrotta //Connection terminated with server

my_client exited with code 0

So, basically the server sends his welcome message, but then it goes on loop without printing anything on his own terminal, while it should at least print "Server started" and wait for the client input and react, plus the client loses the connection to the server and doesn't take the user input as requested, which should not happen. I didn't have all these problems when testing on my Ubuntu virtual machine. For reference this is my server code which sends the message you have seen to the client:

void* connection_handler(void* conn_fd) {
int fd = *(int*) conn_fd;
free(conn_fd);
printf("Gestendo richiesta client %d...\n", fd);
char buffer[256];
int byte_letti = sprintf(buffer, "Benvenuto! Cosa vuoi fare? Premi:\n"
    "1 Per unirti a una partita\n"
    "2 Per creare una partita\n"
    "Qualsiasi altro tasto per uscire\n");
buffer[byte_letti] = 0;
send(fd, buffer, byte_letti, 0);

byte_letti=recv(fd, buffer, 256, 0);
buffer[byte_letti]=0;
// printf("Ricevuto: %s\n", buffer); // Debug per vedere il messaggio ricevuto

int scelta = atoi(buffer);
// printf("Scelta convertita: %d\n", scelta); // Debug
switch (scelta) {
    case 1: //Un giocatore si unisce ad una partita
        // printf("SCELTO 1\n");
        send_game_list(fd);
        int chosen_game = wait_game_choice(fd);
        if (chosen_game != -1) {
            Game* gameFound = find_game_and_join(chosen_game, fd);
            while(gameFound==NULL) { //gestione del caso l'input non sia giusto lato server
                // if (gameFound != NULL) {
                //     printf("QUI!\n");
                //     sprintf(buffer, "Partita trovata!\n");
                //     send(fd, buffer, strlen(buffer), 0);
                //     break;
                // } else {
                    sprintf(buffer, "Nessuna partita corrisponde a quella scelta! Riprovare.\n");
                    send(fd, buffer, strlen(buffer), 0);
                    chosen_game = wait_game_choice(fd);
                    gameFound = find_game_and_join(chosen_game, fd);
                    continue;
                // }
            }
            play_game(gameFound, fd);
        }
        break;
    case 2: //Un giocatore crea una partita
        Game* createdGame = create_and_join(fd); //Operazione bloccante finché un altro giocatore non si unisce
        initialize_game(createdGame);
        play_game(createdGame, fd);
        break;
    default:
        close(fd);
        removeClientFromList(fd);
        printf("Connessione con il client %d interrotta\n", fd);
}

} As you can see its much more complex, but it seems like it's going on loop while not printing anything while the client just terminates all of a sudden, what is happening? This is the client code for reference:

void clientActions()
{
    nbytes=recv(socket_fd, buffer, 256, 0);
    buffer[nbytes]=0;
    printf("%s", buffer);

    int scelta;
    scanf("%d", &scelta);
    // getchar();
    snprintf(buffer, sizeof(buffer), "%d", scelta);
    send(socket_fd, buffer, strlen(buffer), 0);
    

    switch (scelta) {
        case 1:
            receiveGamesList();
            chooseGame();
            waitJoinConfirmed(); 
            gameLoop();
            break;
        case 2:
            createGame();
            break;
        default:
            close(socket_fd);
            printf("Connessione con il server interrotta\n");
    }
}

I have my client-side code like this where the constant SOCKET_PATH is "/tmp/my_socket":

#define SOCKET_PATH "/tmp/my_socket"
//rest of the code

int main(int argc, char *argv[])
{
    struct sockaddr_un server_addr;

    server_addr.sun_family = AF_LOCAL; /*socket locali*/
    strcpy(server_addr.sun_path, SOCKET_PATH);

    if ((socket_fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0)
    {
        perror("Errore creazione welcoming socket");
        return 1;
    }

    if ((connect(socket_fd,
                 (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0))
    {
        perror("Errore connect");
        return 1;
    }

    clientActions();

    /*Pulizia prima della terminazione*/
    close(socket_fd);
    return 0;
}

My server-side is like this:

#define SOCKET_PATH "/tmp/my_socket"
//rest of the code

int main(int argc, char* argv[]) {
    int socket_fd, conn_fd;
    struct sockaddr_un server_addr, client_addr;

    server_addr.sun_family=AF_LOCAL; /*socket locali*/
    unlink(SOCKET_PATH); /*Rimuove la socket se già esiste*/

    strcpy(server_addr.sun_path, SOCKET_PATH);

    printf("Server in esecuzione...\n");
    sleep(1);

    if ((socket_fd=socket(PF_LOCAL,SOCK_STREAM,0)) < 0){
        perror("Errore creazione welcoming socket");
        return 1;
    }
    
    if ((bind(socket_fd,
    (struct sockaddr*)&server_addr,sizeof(server_addr))<0)) {
        perror("Errore bind strano");
        return 1;
    }

    if ((listen(socket_fd, 5)) < 0){ /*5 è la dim della coda di attesa*/
        perror("Errore nel listen");
        return 1;
    }

    while (1) {
        if ((conn_fd = accept(socket_fd,NULL,NULL)) < 0) {
            perror("Errore accept");
            return 1;
        }
        addClientToList(conn_fd);
        pthread_t tid;
        int* conn_fd_ptr = malloc(sizeof(int));
        *conn_fd_ptr = conn_fd; //Per evitare problemi con var condivise
        // TODO: gestione thread
        if (pthread_create(&tid, NULL, connection_handler, conn_fd_ptr) != 0) {
            perror("Errore creazione thread");
            free(conn_fd_ptr);
            close(conn_fd);
            removeClientFromList(conn_fd);
            continue;
        }

        pthread_detach(tid);
    }

    /*Pulizia prima della terminazione*/
    close(socket_fd);
    unlink(SOCKET_PATH);
    return 0;
}

Executing the code without docker using gcc compiler on my Ubuntu Virtual Machine works fine. But when I have to use docker compose something goes wrong about the server side binding. This is the Dockerfile.server:

FROM gcc:11.4

# Crea una cartella per l'app
RUN mkdir -p /opt/app
WORKDIR /opt/app

# Copia i file del server
COPY server.c /opt/app

# Compila il server e collega la libreria pthread
RUN gcc -o server.out server.c -lpthread

# EXPOSE 9200

CMD ["./server.out"]

This is the Dockerfile.client:

FROM gcc:11.4

# Crea una cartella per l'app
RUN mkdir -p /opt/app
WORKDIR /opt/app

# Copia i file del client
COPY client.c /opt/app

# Compila il client e collega la libreria pthread
RUN gcc -o client.out client.c -lpthread

CMD ["./client.out"]

And finally my docker compose is this:

version: '3'
services:
  server:
    build:
      context: .
      dockerfile: Dockerfile.server
    container_name: my_server
    # ports:
    #   - "9000:9100"  # Espone la porta del server sulla macchina host
    volumes:
      - /tmp/my_socket:/tmp/my_socket  # Condivide il socket file

  client:
    build:
      context: .
      dockerfile: Dockerfile.client
    container_name: my_client
    depends_on:
      - server  # Il client parte solo dopo che il server è pronto
    volumes:
      - /tmp/my_socket:/tmp/my_socket  # Usa lo stesso socket file

The error that docker gives me when I'm trying to do docker compose up --build is like this:

[+] Running 3/3
 ✔ Network progettotrislso_default  Created                                                                          0.1s 
 ✔ Container my_server              Created                                                                          0.2s 
 ✔ Container my_client              Created                                                                          0.3s 
Attaching to my_client, my_server
my_client  | Errore connect: Connection refused
my_client exited with code 1
my_server  | Server in esecuzione...
my_server  | Errore bind strano: Address already in use
my_server exited with code 1

I can understand the client error, but why the server error? On my ubuntu it works just fine, what is happening? Does that have to do with the docker volumes?

EDIT

So I've tried to use named volumes as suggested and now my docker compose file looks like this:

    version: '3'

volumes:
  socket:  # Definiamo un volume nominato

services:
  server:
    build:
      context: .
      dockerfile: Dockerfile.server
    container_name: my_server
    # ports:
    #   - "9000:9100"  # Espone la porta del server sulla macchina host
    volumes:
      - socket:/tmp # Condivide il socket file

  client:
    build:
      context: .
      dockerfile: Dockerfile.client
    container_name: my_client
    depends_on:
      - server  # Il client parte solo dopo che il server è pronto
    volumes:
      - socket:/tmp  # Usa lo stesso socket file

When I run docker compose --build now there is no more bind error, however the output now is like this:

[+] Running 2/2

✔ Container my_client Recreated 11.5s ✔ Container my_server Recreated 11.1s Attaching to my_client, my_server

my_client | Benvenuto! Cosa vuoi fare? Premi: //This is my menu

my_client | 1 Per unirti a una partita

my_client | 2 Per creare una partita

my_client | Qualsiasi altro tasto per uscire

my_client | Connessione con il server interrotta //Connection terminated with server

my_client exited with code 0

So, basically the server sends his welcome message, but then it goes on loop without printing anything on his own terminal, while it should at least print "Server started" and wait for the client input and react, plus the client loses the connection to the server and doesn't take the user input as requested, which should not happen. I didn't have all these problems when testing on my Ubuntu virtual machine. For reference this is my server code which sends the message you have seen to the client:

void* connection_handler(void* conn_fd) {
int fd = *(int*) conn_fd;
free(conn_fd);
printf("Gestendo richiesta client %d...\n", fd);
char buffer[256];
int byte_letti = sprintf(buffer, "Benvenuto! Cosa vuoi fare? Premi:\n"
    "1 Per unirti a una partita\n"
    "2 Per creare una partita\n"
    "Qualsiasi altro tasto per uscire\n");
buffer[byte_letti] = 0;
send(fd, buffer, byte_letti, 0);

byte_letti=recv(fd, buffer, 256, 0);
buffer[byte_letti]=0;
// printf("Ricevuto: %s\n", buffer); // Debug per vedere il messaggio ricevuto

int scelta = atoi(buffer);
// printf("Scelta convertita: %d\n", scelta); // Debug
switch (scelta) {
    case 1: //Un giocatore si unisce ad una partita
        // printf("SCELTO 1\n");
        send_game_list(fd);
        int chosen_game = wait_game_choice(fd);
        if (chosen_game != -1) {
            Game* gameFound = find_game_and_join(chosen_game, fd);
            while(gameFound==NULL) { //gestione del caso l'input non sia giusto lato server
                // if (gameFound != NULL) {
                //     printf("QUI!\n");
                //     sprintf(buffer, "Partita trovata!\n");
                //     send(fd, buffer, strlen(buffer), 0);
                //     break;
                // } else {
                    sprintf(buffer, "Nessuna partita corrisponde a quella scelta! Riprovare.\n");
                    send(fd, buffer, strlen(buffer), 0);
                    chosen_game = wait_game_choice(fd);
                    gameFound = find_game_and_join(chosen_game, fd);
                    continue;
                // }
            }
            play_game(gameFound, fd);
        }
        break;
    case 2: //Un giocatore crea una partita
        Game* createdGame = create_and_join(fd); //Operazione bloccante finché un altro giocatore non si unisce
        initialize_game(createdGame);
        play_game(createdGame, fd);
        break;
    default:
        close(fd);
        removeClientFromList(fd);
        printf("Connessione con il client %d interrotta\n", fd);
}

} As you can see its much more complex, but it seems like it's going on loop while not printing anything while the client just terminates all of a sudden, what is happening? This is the client code for reference:

void clientActions()
{
    nbytes=recv(socket_fd, buffer, 256, 0);
    buffer[nbytes]=0;
    printf("%s", buffer);

    int scelta;
    scanf("%d", &scelta);
    // getchar();
    snprintf(buffer, sizeof(buffer), "%d", scelta);
    send(socket_fd, buffer, strlen(buffer), 0);
    

    switch (scelta) {
        case 1:
            receiveGamesList();
            chooseGame();
            waitJoinConfirmed(); 
            gameLoop();
            break;
        case 2:
            createGame();
            break;
        default:
            close(socket_fd);
            printf("Connessione con il server interrotta\n");
    }
}

Share Improve this question edited Mar 18 at 19:30 Arteteca asked Mar 18 at 15:05 ArtetecaArteteca 291 silver badge3 bronze badges 4
  • Does it work to mount the directory containing the socket, rather than the socket itself? I'd also consider using a Docker named volume here instead of a host directory (especially if you're on a VM-based setup like Docker Desktop). A TCP socket will be easier still. – David Maze Commented Mar 18 at 16:52
  • I am indeed using Docker Desktop for this. I tried what you said and instead of '/tmp/my_socket:/tmp/my_socket' I put '/tmp:/tmp' and I got the same error on the bind() function, I even tried to put '/tmp/:/tmp/' to sse if something could change, but nope the server still gives me the same error and I can't understand why – Arteteca Commented Mar 18 at 17:26
  • Does a named volume work; specify volumes: { socket: } at the top level of the file, and then use volumes: ['socket:/tmp'] on the two services? – David Maze Commented Mar 18 at 17:44
  • Named volume actually helped me, but didn't completely solve the problem. I'm gonna edit my question to add more details. – Arteteca Commented Mar 18 at 18:54
Add a comment  | 

1 Answer 1

Reset to default 1

Unix sockets are a kernel-managed pass-through from one process to another. The most reliable way to make them work is to create a Docker named volume to hold the socket's directory and mount that same volume into both containers.

In your example the socket is stored in /tmp so your setup would need to look like

version: '3.8'
services:
  server:
    ...

    volumes:
      - socket:/tmp
  client:
    volumes:
      - socket:/tmp
volumes:
  socket:

The thing you mount – the right-hand side of the per-service volumes: line – must be a directory in this case. In standard Unix you can only mount directories; Docker has some ability to mount individual files, but it doesn't work for "special" files like sockets, and it doesn't work if the file doesn't exist yet.

The other important detail is that a Unix socket is specific to a kernel. If you're using Docker Desktop or another similar VM-based setup, you will have both your host kernel and also the separate kernel running in the Docker VM. This means you can't necessarily use a Unix socket to communicate between the container and the host, and depending on the specific filesystem setup, a bind mount may not work. (If you're using Docker Engine directly on a native-Linux host, the host's kernel is shared with containers and bind mounts should work.)


You added an additional issue around the container trying to read from its own stdin, and immediately exiting. Services that depend on direct console I/O don't necessarily run well in Compose. You can use the stdin_open: option to make sure there is a stdin; if you don't have this option, your process will see a closed file descriptor and immediately exit.

Even then, you won't be able to type at your process using native Compose commands. You need to use docker attach to start typing into the running container, which involves finding the container name (or manually specifying it with Compose container_name:).

Also see docker-compose up and user inputs on stdin.

本文标签: