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
|
1 Answer
Reset to default 1Unix 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.
本文标签:
版权声明:本文标题:c - How can I make my local client-server application communicate on a local socket using docker compose? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744505708a2609582.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
volumes: { socket: }
at the top level of the file, and then usevolumes: ['socket:/tmp']
on the two services? – David Maze Commented Mar 18 at 17:44