OVH Cloud OVH Cloud

Socket UDP en broadcast

83 réponses
Avatar
Thomas Nemeth
Bonjour !

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.

Thomas.

10 réponses

Avatar
Laurent Wacrenier
Bob qui Trolle écrit:
Ce que tu décris ressemble beaucoup à SNMP


Pas trop. C'est plus proche de ntpd.

Avatar
Thomas Nemeth
Laurent Wacrenier a tapoté :

Thomas Nemeth écrit:
Maintenant il faudrait que j'étudie la possibilité de faire en
sorte que l'un des clients puisse contacter le serveur afin de le
faire changer de mode de fonctionnement. Je pense qu'un select
dans un autre thread permettrait de se mettre en attente de
lecture...


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 :)


Thomas.


Avatar
Laurent Wacrenier
Thomas Nemeth écrit:
Après avoir fouillé les différentes pages man j'ai des difficultés à
saisir la façon de se servir de bind() et connect(). Pour socket(),
accept(), (set|get)sockopt(), send[to](), recv[from](), je vois bien
mais l'utilité de bind() et connect() ne me semble pas claire (bien
qu'indispensable) et je les utilise donc de façon robotique sans
trop comprendre les mécanismes sous-jacents.


connect() envoie une demande de connexion. Comme son nom l'indique, ça
ne sert qu'en mode connecté (TCP).

accept() reçoit les demandes de connexion.

bind() associe une adresse à une socket.
Il faut l'utiliser avant connect() pour avoir où on se connecte ou
accept() pour savoir sur quoi on attend.

Avant accept() (et après bind()), il faut aussi faire un listen()
pour parametrer la queue d'acceptation de connexion.

Avatar
Thomas Nemeth
Christophe Blaess a tapoté :

avec UDP, tu utilises sendto() pour donner les port/addresse
destination.


Groumph :(
Pas possible de faire un bind() suivi de plusieurs send() dans ce
cas ?


Il est possible d'utiliser connect() sur une socket UDP
(en donnant l'adresse d'un correspondant). Dans ce cas


Sauf que... Dans ce cas c'est du broadcast (du moins pour la partie
que je décrivais) et que je ne connais pas les correspondants.


Thomas.



Avatar
Laurent Wacrenier
Thomas Nemeth écrit:
Ce qui me pose pb c'est : est-ce que bind() permet d'utiliser
send() et non sendto() (puisque bind "affecte un <<nom>> à une
socket" mais la page man ne parle pas de <<connexion>>) ?


Il aurait pu, ne serait-ce que par homogénéité avec recv(), mais il ne
peut pas.

Avatar
Thomas Nemeth
Laurent Wacrenier a tapoté :

Thomas Nemeth écrit:
Après avoir fouillé les différentes pages man j'ai des
difficultés à saisir la façon de se servir de bind() et
connect(). Pour socket(), accept(), (set|get)sockopt(),
send[to](), recv[from](), je vois bien mais l'utilité de bind()
et connect() ne me semble pas claire (bien qu'indispensable) et
je les utilise donc de façon robotique sans trop comprendre les
mécanismes sous-jacents.


connect() envoie une demande de connexion. Comme son nom l'indique, ça
ne sert qu'en mode connecté (TCP).

bind() associe une adresse à une socket.
Il faut l'utiliser avant connect() pour avoir où on se connecte ou
accept() pour savoir sur quoi on attend.


Oui. C'est ce que j'ai trouvé dans les docs en ligne par la suite
et ce que m'a dit Viêt Hoà (si c'est comme ça que je dois l'écrire).
Comme je l'ai écrit précédemment, ce qui est étrange c'est que
bind() permette d'associer un adresse et un port à une socket mais
qu'on ne peut(pourrait) pas utiliser send() par la suite.


Thomas.


Avatar
Laurent Wacrenier
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.


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.


Le fait que les autres clients recoivent la commande n'est pas un pb
puisqu'ils pourront faire un traitement discriminatif sur les
données reçues.

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()

while (cont) sendto(broadcast) // dans un autre thread


Plutôt sendto() vers l'adresse récupérée par le recvfrom().

Avatar
Thomas Nemeth
Laurent Wacrenier a tapoté :

Thomas Nemeth écrit:
Ce qui me pose pb c'est : est-ce que bind() permet d'utiliser
send() et non sendto() (puisque bind "affecte un <<nom>> à une
socket" mais la page man ne parle pas de <<connexion>>) ?


Il aurait pu, ne serait-ce que par homogénéité avec recv(), mais il ne
peut pas.


Bon, ok, tant pis...

Merci pour tout, en tout cas, vous m'avez tous bien aidé !


Thomas.


Avatar
Laurent Wacrenier
Christophe Blaess écrit:
Il est possible d'utiliser connect() sur une socket UDP
(en donnant l'adresse d'un correspondant).


Pas dans l'univers connu.

Avatar
Laurent Wacrenier
Nicolas George <nicolas$ écrit:
En UDP, connect est possible également : il revient à fixer une destination
implicite pour les paquets envoyés avec send tout court, et à ignorer les
paquets qui ne viennent pas de l'adresse correspondante.


S'il n'y a qu'une seule adresse, ça se règle avec un bind().