Je cherche à émettre des données (une chaîne de 30 caractères) en
broadcast UDP. Si je sais me débrouiller pour les socket TCP (et encore
je n'ai pas tenté le broadcast), pour les sockets UDP j'ai du mal à voir
comment configurer la socket afin de pouvoir écrire à partir d'une
machine et lire à partir de plusieurs autres.
Jusque-là, pour mes serveurs, je faisais la recette habituelle :
- pour les serveurs :
socket()
setsockopt() pour REUSEADDR et LINGER
bind()
listen()
- pour les clients :
socket()
setsockopt() (idem)
bind()
connect()
Or pour les sockets UDP en broadcast, je ne vois pas trop comment
faire. Pour l'instant (ce qui ne marche pas) :
socket()
setsockopt() pour REUSEADDR et BROADCAST
connect()
Puis write() ou send() pour écrire et read() ou recv() pour lire.
Quelqu'un a-t-il une idée sur la méthode à appliquer ?
Merci d'avance.
Pas besoin de select() s'il y a des threads. Il suffit de bloquer sur recvfrom() avec une socket de controle sur un autre port.
Si si : dans ce thread j'attend aussi des connexions sur RS :)
Une fois que tu as deux threads, tu peux en avoir trois.
Thomas Nemeth
Laurent Wacrenier a tapoté :
Thomas Nemeth écrit:
- clients : reçoivent en permanence ces données. socket() setsockopt() while (cond) recvfrom()
Il manque un bind() pour définir l'adresse et le port d'attente.
Hum... recvfrom() ne le fait pas ?
Mais si je veux pouvoir faire en sorte qu'un des clients envoie une commande de changement de type de données au serveur, il faut que le serveur puisse écouter... Or écouter sur du broadcast alors qu'on y écrit soi-même peut être un poil gênant, non ? Le serveur risque de recevoir ses propres messages et donc croire qu'il reçoit une demande de connexion.
Mieux vaut utiliser un autre port pour le controle.
Effectivement, cependant ça m'oblige à ouvrir une nouvelle socket. C'est une solution à envisager : je la garde sous le coude :)
Y aurait-il la possibilité pour le serveur de faire un truc dans le genre : socket() setsockopt() bind() // sur l'adresse locale recv() // dans un thread
recvfrom()
Ok.
while (cont) sendto(broadcast) // dans un autre thread
Plutôt sendto() vers l'adresse récupérée par le recvfrom().
Pas possible : le cahier des charges dit que ça doit obligatoirement être du broadcast. J'aurais effectivement préféré faire du client/serveur au sens habituel (puisque j'ai déjà fait plusieurs programmes sur le modèle -- via TCP) mais malheureusement ce n'est pas possible.
Le recvfrom() dans le 1er thread sert uniquement à savoir quand basculer d'un mode d'émission à un autre. Alors que le sendto() est destiné à balancer les données en permanences sur le broadcast.
Thomas.
Laurent Wacrenier a tapoté :
Thomas Nemeth <thomas.nemeth@betatech.invalid> écrit:
- clients : reçoivent en permanence ces données.
socket()
setsockopt()
while (cond) recvfrom()
Il manque un bind() pour définir l'adresse et le port d'attente.
Hum... recvfrom() ne le fait pas ?
Mais si je veux pouvoir faire en sorte qu'un des clients envoie
une commande de changement de type de données au serveur, il faut
que le serveur puisse écouter... Or écouter sur du broadcast
alors qu'on y écrit soi-même peut être un poil gênant, non ? Le
serveur risque de recevoir ses propres messages et donc croire
qu'il reçoit une demande de connexion.
Mieux vaut utiliser un autre port pour le controle.
Effectivement, cependant ça m'oblige à ouvrir une nouvelle socket.
C'est une solution à envisager : je la garde sous le coude :)
Y aurait-il la possibilité pour le serveur de faire un truc dans
le genre :
socket()
setsockopt()
bind() // sur l'adresse locale
recv() // dans un thread
recvfrom()
Ok.
while (cont) sendto(broadcast) // dans un autre thread
Plutôt sendto() vers l'adresse récupérée par le recvfrom().
Pas possible : le cahier des charges dit que ça doit obligatoirement
être du broadcast. J'aurais effectivement préféré faire du
client/serveur au sens habituel (puisque j'ai déjà fait plusieurs
programmes sur le modèle -- via TCP) mais malheureusement ce n'est
pas possible.
Le recvfrom() dans le 1er thread sert uniquement à savoir quand
basculer d'un mode d'émission à un autre. Alors que le sendto() est
destiné à balancer les données en permanences sur le broadcast.
- clients : reçoivent en permanence ces données. socket() setsockopt() while (cond) recvfrom()
Il manque un bind() pour définir l'adresse et le port d'attente.
Hum... recvfrom() ne le fait pas ?
Mais si je veux pouvoir faire en sorte qu'un des clients envoie une commande de changement de type de données au serveur, il faut que le serveur puisse écouter... Or écouter sur du broadcast alors qu'on y écrit soi-même peut être un poil gênant, non ? Le serveur risque de recevoir ses propres messages et donc croire qu'il reçoit une demande de connexion.
Mieux vaut utiliser un autre port pour le controle.
Effectivement, cependant ça m'oblige à ouvrir une nouvelle socket. C'est une solution à envisager : je la garde sous le coude :)
Y aurait-il la possibilité pour le serveur de faire un truc dans le genre : socket() setsockopt() bind() // sur l'adresse locale recv() // dans un thread
recvfrom()
Ok.
while (cont) sendto(broadcast) // dans un autre thread
Plutôt sendto() vers l'adresse récupérée par le recvfrom().
Pas possible : le cahier des charges dit que ça doit obligatoirement être du broadcast. J'aurais effectivement préféré faire du client/serveur au sens habituel (puisque j'ai déjà fait plusieurs programmes sur le modèle -- via TCP) mais malheureusement ce n'est pas possible.
Le recvfrom() dans le 1er thread sert uniquement à savoir quand basculer d'un mode d'émission à un autre. Alors que le sendto() est destiné à balancer les données en permanences sur le broadcast.
Thomas.
Thomas Nemeth
Laurent Wacrenier a tapoté :
Thomas Nemeth écrit:
Pas besoin de select() s'il y a des threads. Il suffit de bloquer sur recvfrom() avec une socket de controle sur un autre port.
Si si : dans ce thread j'attend aussi des connexions sur RS :)
Une fois que tu as deux threads, tu peux en avoir trois.
En fait ce ne sont pas vraiment des threads. J'en ai parler pour me simplifier l'explication. La partie qui émet les données en permanence est faite par interruption alors que celle qui attend les connexions RS et UDP pour changer le mode d'émission est le programme principal utilisant déjà select().
Cependant je ne vois pas trop où serait le pb de rajouter la socket dans la liste des fdsets de réception pour select()...
Thomas.
Laurent Wacrenier a tapoté :
Thomas Nemeth <thomas.nemeth@betatech.invalid> écrit:
Pas besoin de select() s'il y a des threads. Il suffit de bloquer
sur recvfrom() avec une socket de controle sur un autre port.
Si si : dans ce thread j'attend aussi des connexions sur RS :)
Une fois que tu as deux threads, tu peux en avoir trois.
En fait ce ne sont pas vraiment des threads. J'en ai parler pour
me simplifier l'explication. La partie qui émet les données en
permanence est faite par interruption alors que celle qui attend
les connexions RS et UDP pour changer le mode d'émission est le
programme principal utilisant déjà select().
Cependant je ne vois pas trop où serait le pb de rajouter la socket
dans la liste des fdsets de réception pour select()...
Pas besoin de select() s'il y a des threads. Il suffit de bloquer sur recvfrom() avec une socket de controle sur un autre port.
Si si : dans ce thread j'attend aussi des connexions sur RS :)
Une fois que tu as deux threads, tu peux en avoir trois.
En fait ce ne sont pas vraiment des threads. J'en ai parler pour me simplifier l'explication. La partie qui émet les données en permanence est faite par interruption alors que celle qui attend les connexions RS et UDP pour changer le mode d'émission est le programme principal utilisant déjà select().
Cependant je ne vois pas trop où serait le pb de rajouter la socket dans la liste des fdsets de réception pour select()...
Thomas.
Laurent Wacrenier
Thomas Nemeth écrit:
Il manque un bind() pour définir l'adresse et le port d'attente.
Hum... recvfrom() ne le fait pas ?
Et pourquoi le paquet irait à ton démon et pas à un autre ? L'adresse en argument de recvfrom() est celle à la source du paquet.
Effectivement, cependant ça m'oblige à ouvrir une nouvelle socket. C'est une solution à envisager : je la garde sous le coude :)
Mieux vaut éviter les dialogues en broadcast. Ça fini en dialogues de sourds et en inondations du réseau.
Thomas Nemeth <thomas.nemeth@betatech.invalid> écrit:
Il manque un bind() pour définir l'adresse et le port d'attente.
Hum... recvfrom() ne le fait pas ?
Et pourquoi le paquet irait à ton démon et pas à un autre ?
L'adresse en argument de recvfrom() est celle à la source du paquet.
Effectivement, cependant ça m'oblige à ouvrir une nouvelle socket.
C'est une solution à envisager : je la garde sous le coude :)
Mieux vaut éviter les dialogues en broadcast.
Ça fini en dialogues de sourds et en inondations du réseau.
Cependant je ne vois pas trop où serait le pb de rajouter la socket dans la liste des fdsets de réception pour select()...
Oui s'il n'y a pas de threads. Sinon c'est de la programation mixte avec bugs venant de plusieurs cotés à la fois.
Nicolas George
Laurent Wacrenier wrote in message :
S'il n'y a qu'une seule adresse, ça se règle avec un bind().
bind, ça règle l'adresse locale, ça n'a rien à voir. Au vu de quelques autres messages, une petite révision de la doc de connect s'impose :
« If the initiating socket is not connection-mode, then connect() shall set the socket's peer address, and no connection is made. For SOCK_DGRAM sockets, the peer address identifies where all datagrams are sent on subsequent send() functions, and limits the remote sender for subsequent recv() functions. If address is a null address for the protocol, the socket's peer address shall be reset. »
Laurent Wacrenier wrote in message
<slrndb5eb6.1c3e.lwa@victor.teaser.fr>:
S'il n'y a qu'une seule adresse, ça se règle avec un bind().
bind, ça règle l'adresse locale, ça n'a rien à voir. Au vu de quelques
autres messages, une petite révision de la doc de connect s'impose :
« If the initiating socket is not connection-mode, then connect() shall set
the socket's peer address, and no connection is made. For SOCK_DGRAM
sockets, the peer address identifies where all datagrams are sent on
subsequent send() functions, and limits the remote sender for subsequent
recv() functions. If address is a null address for the protocol, the
socket's peer address shall be reset. »
S'il n'y a qu'une seule adresse, ça se règle avec un bind().
bind, ça règle l'adresse locale, ça n'a rien à voir. Au vu de quelques autres messages, une petite révision de la doc de connect s'impose :
« If the initiating socket is not connection-mode, then connect() shall set the socket's peer address, and no connection is made. For SOCK_DGRAM sockets, the peer address identifies where all datagrams are sent on subsequent send() functions, and limits the remote sender for subsequent recv() functions. If address is a null address for the protocol, the socket's peer address shall be reset. »
Nicolas George
Laurent Wacrenier wrote in message :
L'adresse en argument de recvfrom() est celle à la source du paquet.
Précisons : l'adresse en argument à recvfrom est un pointeur qui sert à fournir en *retour* l'adresse source du paquet.
Laurent Wacrenier wrote in message
<slrndb5f4j.1c3e.lwa@victor.teaser.fr>:
L'adresse en argument de recvfrom() est celle à la source du paquet.
Précisons : l'adresse en argument à recvfrom est un pointeur qui sert à
fournir en *retour* l'adresse source du paquet.
Il manque un bind() pour définir l'adresse et le port d'attente.
Hum... recvfrom() ne le fait pas ?
Et pourquoi le paquet irait à ton démon et pas à un autre ? L'adresse en argument de recvfrom() est celle à la source du paquet.
Je pensais, bêtement, que ça suffisait pour que la socket reçoive les paquets transitant par l'adresse et le port spécifié...
Effectivement, cependant ça m'oblige à ouvrir une nouvelle socket. C'est une solution à envisager : je la garde sous le coude :)
Mieux vaut éviter les dialogues en broadcast. Ça fini en dialogues de sourds et en inondations du réseau.
Je le note :)
Merci pour tout !
Thomas.
Laurent Wacrenier
Thomas Nemeth écrit:
Je pensais, bêtement, que ça suffisait pour que la socket reçoive les paquets transitant par l'adresse et le port spécifié...
recvfrom() ne spécifie pas d'adresse ou de port, d'où le bind(). Il récupère juste celle de l'éméteur (en mode connecté on aurait l'information avec getpeername()).
Thomas Nemeth <thomas.nemeth@betatech.invalid> écrit:
Je pensais, bêtement, que ça suffisait pour que la socket reçoive
les paquets transitant par l'adresse et le port spécifié...
recvfrom() ne spécifie pas d'adresse ou de port, d'où le bind(). Il
récupère juste celle de l'éméteur (en mode connecté on aurait
l'information avec getpeername()).
Je pensais, bêtement, que ça suffisait pour que la socket reçoive les paquets transitant par l'adresse et le port spécifié...
recvfrom() ne spécifie pas d'adresse ou de port, d'où le bind(). Il récupère juste celle de l'éméteur (en mode connecté on aurait l'information avec getpeername()).
Thomas Nemeth
Laurent Wacrenier a tapoté :
Thomas Nemeth écrit:
Je pensais, bêtement, que ça suffisait pour que la socket reçoive les paquets transitant par l'adresse et le port spécifié...
recvfrom() ne spécifie pas d'adresse ou de port, d'où le bind(). Il récupère juste celle de l'éméteur (en mode connecté on aurait l'information avec getpeername()).
Ok, donc son utilisation ne nécessite pas de lui passer une variable sockaddr_in paramétrée, mais sert plutôt à stocker les données venant de l'émetteur. Effectivement (après un détour par le man) c'est bien ce que dit entre les lignes la description de la fonction...
Thomas.
Laurent Wacrenier a tapoté :
Thomas Nemeth <thomas.nemeth@betatech.invalid> écrit:
Je pensais, bêtement, que ça suffisait pour que la socket reçoive
les paquets transitant par l'adresse et le port spécifié...
recvfrom() ne spécifie pas d'adresse ou de port, d'où le bind(). Il
récupère juste celle de l'éméteur (en mode connecté on aurait
l'information avec getpeername()).
Ok, donc son utilisation ne nécessite pas de lui passer une variable
sockaddr_in paramétrée, mais sert plutôt à stocker les données
venant de l'émetteur.
Effectivement (après un détour par le man) c'est bien ce que dit
entre les lignes la description de la fonction...
Je pensais, bêtement, que ça suffisait pour que la socket reçoive les paquets transitant par l'adresse et le port spécifié...
recvfrom() ne spécifie pas d'adresse ou de port, d'où le bind(). Il récupère juste celle de l'éméteur (en mode connecté on aurait l'information avec getpeername()).
Ok, donc son utilisation ne nécessite pas de lui passer une variable sockaddr_in paramétrée, mais sert plutôt à stocker les données venant de l'émetteur. Effectivement (après un détour par le man) c'est bien ce que dit entre les lignes la description de la fonction...