Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Comment avoir une socket datagram bidirectionnelle locale a un Linux ?

2 réponses
Avatar
David MENTRE
Bonjour à tous,

Je voudrais faire communiquer 2 processus sur un même Linux (Debian,
noyau 2.6.3) par une socket bidirectionnelle datagram (càd qui conserve
la séparation entre les message, une socket stream m'oblige à refaire la
segmentation).

Après avoir lu un certain nombre de pages de man (unix(7), socket(2),
...) il me semblait que PF_UNIX, SOCK_DGRAM pouvait convenir.

J'ai donc écrit le code suivant. J'arrive à envoyer un message de la
machine B (qui fait le connect()) à la machine A.

Par contre, quand la machine A envoie un message à B, j'ai droit à un
joli :

cannot send message: Transport endpoint is not connected


Est-ce qu'une socket PF_UNIX, SOCK_DGRAM est unidirectionnelle ? Il me
faut ouvrir 2 sockets (A->B et B->A) ?

J'ai oublié une manip' ou option dans le code suivant ?

Est-ce qu'il existe un autre type de socket qui me permet de réaliser ce
que je veux ?


Merci d'avance pour tout coup de main,
Amicalement,
david


void micom_init(enum micom_side_t side)
{
struct sockaddr_un sock_addr = { AF_UNIX, SOCKET_FILE_NAME };

my_side = side;
switch (my_side) {
case A_SIDE:
/* on A side, open server socket */
if (debug)
printf("creating A side socket...\n");
com_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
if (com_socket < 0) {
perror("unable to open micom socket");
exit(1);
}
if (bind(com_socket, (struct sockaddr *)&sock_addr,
sizeof(struct sockaddr_un)) < 0) {
perror("unable to bind micom socket (/tmp/micom_A_B already exists?)");
exit(1);
}
if (debug) printf(" done.\n");
break;

case B_SIDE:
/* on B side, connect to the above socket */
if (debug) printf("creating B side socket and connect to A side...\n");
com_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
if (com_socket < 0) {
perror("unable to open micom socket");
exit(1);
}
if (connect(com_socket, (struct sockaddr*)&sock_addr,
sizeof(struct sockaddr_un)) < 0) {
perror("unable to connect to A side");
exit(1);
}
if (debug) printf(" connection made.\n");
break;

default:
printf("micom_init(sim): undefined side, abort.\n");
exit(1);
}
}

void micom_close(void)
{
switch (my_side) {
case A_SIDE:
case B_SIDE:
close(com_socket);
unlink(SOCKET_FILE_NAME);
break;

default:
abort();
}
}

void micom_send_msg(uint8_t *message_buffer, int size)
{
if (send(com_socket, message_buffer, size, 0) < 0) {
perror("cannot send message");
abort();
}
}

void micom_recv_msg(micom_dataless_msg_t *message_buffer, int *size)
{
*size = recv(com_socket, message_buffer, MICOM_MAX_MSG_SIZE, MSG_WAITALL);
}

--
David Mentré

--
Pour contacter l'équipe de modération : moderateurs-fcolm@efrei.fr
ATTENTION: Postez DIRECTEMENT vos articles dans le groupe, PAS dans
la liste de distribution des modérateurs.

2 réponses

Avatar
Brieuc Jeunhomme
> Par contre, quand la machine A envoie un message à B, j'ai droit à un
joli :

cannot send message: Transport endpoint is not connected



C'est logique. Tu n'as pas fait de connect(), et tu ne fais pas non plus
un sendto(), donc, la machine A n'a aucun moyen de savoir à qui envoyer
les données. Il faudrait faire aussi un connect() côté A. Mais un seul
des deux process pourra recevoir les messages (A, en l'occurence).

Est-ce qu'il existe un autre type de socket qui me permet de réaliser ce
que je veux ?



Je n'en ai jamais eu besoin, mais je pense que tu trouveras ton bonheur
dans man socketpair. Autre technique qui pourrait faire ton affaire: les
messages Sys V (man msgctl; man msgget; man msgrcv; man msgsnd), mais ça
a la réputation d'être buggué sous Linux (les bugs se manifestant quand
tu envoies beaucoup de messages en peu de temps).

--
BBP

--
Pour contacter l'équipe de modération :
ATTENTION: Postez DIRECTEMENT vos articles dans le groupe, PAS dans
la liste de distribution des modérateurs.
Avatar
Pascal Dufour
David MENTRE wrote:
Je voudrais faire communiquer 2 processus sur un même Linux (Debian,
noyau 2.6.3) par une socket bidirectionnelle datagram (càd qui conserve
la séparation entre les message, une socket stream m'oblige à refaire la
segmentation).

Après avoir lu un certain nombre de pages de man (unix(7), socket(2),
...) il me semblait que PF_UNIX, SOCK_DGRAM pouvait convenir.

J'ai donc écrit le code suivant. J'arrive à envoyer un message de la
machine B (qui fait le connect()) à la machine A.



Cela ne marchera pas si A est différente de B, par définition.


Par contre, quand la machine A envoie un message à B, j'ai droit à un
joli :

cannot send message: Transport endpoint is not connected

Est-ce qu'une socket PF_UNIX, SOCK_DGRAM est unidirectionnelle ? Il me
faut ouvrir 2 sockets (A->B et B->A) ?



Non, cela fonctionne très bien.


J'ai oublié une manip' ou option dans le code suivant ?



D'après ce que je vois dans le code, vous utilisez "send"/"recv" au
lieu de "sendto"/"recvfrom", cela ne peut fonctionner que si la
socket est "connectée" (sens particulier dans le cas de SOCK_DGRAM).
Dans votre code, B fait un connect, mais pas A.

Vous trouverez de bons exemples ici:

http://www.kohala.com/start/unpv12e/unpv12e.tar.gz

Ce sont les codes sources du livre de Richard Stevens sur la
programmation réseau sous Unix.

Il y a beaucoup de petites subtilités dans la programmation
des sockets. Un bon livre est nécessaire pour éviter les mauvaises
surprises. Les man pages c'est bien comme référence, mais pour la
pédagogie il vaut mieux aller voir ailleur.

--
Pascal.

--
Pour contacter l'équipe de modération :
ATTENTION: Postez DIRECTEMENT vos articles dans le groupe, PAS dans
la liste de distribution des modérateurs.