Comment faire pour re lier un socket udp dans Linux
Je suis un Linux expérimentés en prise de programmeur et suis en train d'écrire une application serveur qui a de nombreuses interfaces sortantes. Maintenant socket serveur se lie à un port aléatoire source dans le début du processus avec INADDR_ANY.
Plus tard, à un certain moment lors de la présentation de la réponse à un nœud spécifique, j'ai besoin d'attribuer un fixe adresse ip source. Le standard de la façon de le faire est d'appeler bind. Cependant, la liaison est appelée une fois pour le numéro de port, les appels successifs échouer avec l'argument non valide erreur.
La création d'un nouveau socket n'est pas vraiment un bon choix étant donné que je vais avoir à le faire très souvent à répondre à certains clients.
J'ai également exploré et une SORTE de beaucoup d'options de prise, comme IP_FREEBIND, mais ce n'est pas tout de suite de mon scénario.
Peut-être en utilisant IP_PKT_INFO et le réglage de l'adresse de la source peut fonctionner à moins qu'il souffre du même problème c'est à dire ne permettant pas une prise une fois lié à INADDRANY à relier à une source fixe ip-ci.
Est-il un moyen de séparer un socket existant ou un autre moyen de réglage de la source de l'adresse ip dans les paquets?
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock < 0)
printf("Failed creating socket\n");
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(1500);
addr.sin_addr.s_addr = INADDR_ANY;
//first bind succeeds
if ( (status = bind(sock, (struct sockaddr *) &addr, sizeof(addr))) < 0)
printf("bind error with port %s\n", strerror(errno));
struct sockaddr_in src_addr;
memset(&src_addr, 0, sizeof(struct sockaddr_in));
src_addr.sin_family = AF_INET;
if (inet_aton("10.0.2.17", &(src_addr.sin_addr)) == 0)
printf("Failed copying address\n");
//second bind fails
if((status = bind(sock, (struct sockaddr *)&src_addr, sizeof(src_addr))) < 0)
printf("re bind error with ip %s\n", strerror(errno));
Toutes les idées à cet égard sera très appréciée. Je suis passé par de nombreux documents sur les sockets, DONC etc. mais sans succès encore.
S'il y a plusieurs interfaces sur le même réseau local, puis créer un socket piscine, un pour chaque carte réseau. Un peu plus en détail est apprécié.
Merci!!!! Prises séparées sont utilisées pour l'envoi et la réception afin de liaison à l'interface de la suite de recvfrom n'a pas d'impact. Et j'ai fait une prise de la piscine aussi. Mais encore l'un d'eux pourrait être nécessaire de choisir un externe fourni ip source. C'est la condition d'application.
encore un d'entre eux pourrait être nécessaire de choisir un externe fourni ip source." Vous dites que vous avez besoin pour gérer les adresses ip source, autres que ceux déjà associés à des interfaces réseau?
Non, c'est un de ceux sur les interfaces. La raison que j'ai mentionné "fournis par l'extérieur", c'est que une liste de configuration est spécifié dans le formulaire d'ip de destination: adresse ip source. Si le courant sortant de destination du paquet est l'une des ip de destination, nous choisissons le source correspondant ip de la liste et l'utiliser comme la prise de la source. Sinon, nous utilisons SOBINDTODEVICE pour l'attacher à un pré configuré l'interface et de l'envoyer.
OriginalL'auteur fayyazkl | 2012-10-03
Vous devez vous connecter pour publier un commentaire.
J'ai enfin trouvé la solution moi-même pour accepter ma propre réponse (sans vergogne, mais bon plugin), complétées par des exemples de code.
Je voulais à l'origine de réécriture d'adresse de la source de l'expédition d'un paquet sans la création de la socket de nouveau où la prise était déjà lié. L'appel de lier plusieurs fois échouer pour ce cas, et (dans mon cas en particulier), je n'étais pas capable d'avoir de l'prises séparées pour chaque ip source et de l'utiliser.
J'ai trouvé quelques références dans IP_PACKET_INFO mais c'était une douleur pour qu'il fonctionne correctement. Référence suivante a été utile.
Réglage de la source de socket udp
Exemple De Code
Ici est une simple application qui permet de créer un socket udp, le lie à un port local, puis avant l'envoi d'un message particulier, il ajoute le sortant de l'adresse ip source. En gardant à l'esprit que dans mon cas, j'ai créé un sudo interface et lui a attribué une autre ip. Envoyer appel échouera si ce n'est pas le cas.
La clé de la déclaration est
où nous sommes en précisant l'adresse ip source pour être utilisé. Le reste des choses comme gsmc struct etc. sont simplement utilisés pour être en mesure d'écrire ipoktinfo struct nous
man 7 ip
page de manuel décrit l'option. Vous n'avez pas vraiment besoin des droits de super-utilisateur: leCAP_NET_ADMIN
capacité est suffisante, c'est à diresudo setcap cap_net_admin=pe binary
est suffisant, pas besoin de le mettre setuid/setgid racine. Cependant, est-il une raison pour laquelle vous ne vous contentez pas d'envoyer la réponse à l'aide d'un nouveau socket, lié à l'adresse de votre choix? Avec UDP, vous n'avez pas besoin d'envoyer la réponse à l'aide de la même prise que la demande a été reçue, comme il n'y a pas de connexion, juste des paquets. Ou le port source de la réponse de la matière pour les clients?Merci, pour l'un, le port de la source de questions. Deuxièmement, dans mon scénario, il est possible que le support lié à cette adresse pourrait être l'entretien d'une autre demande directe, tout en étant lié à l'une des interfaces dire eth2. Où que cette demande doit aller de certains autres éléments d'interface. upvote? 🙂
Car il n'y a pas de connexions, juste des datagrammes, vous pouvez utiliser
sendto()
pour envoyer une réponse à n'importe quelle adresse et le port à partir d'une borne de la prise. Vous pouvez utiliser une seule prise à envoyer des réponses aux différents clients, même simultanément. Les réponses n'ont pas besoin d'utiliser le même socket que la demande a été reçue. Je ne comprends toujours pas pourquoi vous n'avez pas un ensemble fixe de sockets lié à la source désirée, les adresses et les ports. Il serait peut-être plus facile pour voir ce que je veux dire, si j'ai écrit simple exemple de client/serveur comme un nouvel élément de réponse?Je vous remercie. J'ai parfaitement comprendre votre suggestion et n'ont pas besoin de code de référence. Peut-être que mon explication n'est pas à la hauteur. Principalement, j'recevoir des demandes sur une seule demande socket d'écoute. Contre chaque demande correspond une structure allouée, qui contient environ 3 sortant sockets dont chacun est lié à une source différente de port. Pour la vie de cette demande, ces 3 sortant sockets pourriez avoir à envoyer des messages à plusieurs destinations et de recevoir des réponses d'état (à ne pas confondre avec la plaine des demandes). Maintenant j'ai comme 10-15 interfaces. Je ne peut pas avoir 15 sockets par requête
avec chacun étant lié à l'une des interfaces. J'ai besoin de cette requête parce que le port source pour toutes les 3 prises de courant sont différentes pour chaque requête. De sorte qu'un seul socket lié à une adresse ip source ne peut pas être utilisé par de multiples requêtes. Enfin, même si c'était une solution viable, il est un produit fini. La modification principale requête struct et la façon dont il traite les sockets va prendre un mois ou de développement, et environ la même quantité de temps à peaufiner. Et même ce qui ne peut toujours pas obtenir autour de la "dynamique de de port de la source pour chaque réponse de la demande". Merci encore pour l'injection de l'énergie. L'apprécier.
OriginalL'auteur fayyazkl
Il n'y a aucun moyen de les séparer et relier un socket existant.
Jetez un oeil à la solution que j'ai trouvé à l'aide de IP_PACKETINFO et sendmsg. Il n'est pas précisément de relier appel, mais fait le travail, c'est à dire je peux réécrire ma sortant de l'adresse ip sur chaque paquet.
Juste pour votre information: Certains systèmes ne permettent sockets UDP pour être indépendant. Juste lier à une adresse de type AF_UNSPEC. Tout cela renvoie une erreur, la page de man dit, il peut être ignoré. Ensuite, le socket est indépendant et peut être reprise. Bien sûr, ce n'est pas officiellement comportement standardisé et donc pas utile pour un code portable.
La réponse ci-dessus NE TENIR car il n'y a aucun moyen de relier un déjà lié socket [autres que sur les systèmes visés par @Mecki], et N'affirme PAS qu'il n'existe aucun autre moyen de modifier les sortants de l'adresse IP. Et s'il vous PLAÎT JETER HORS de LE CRIER.
L'OP a écrit: Est-il un moyen de séparer un socket existant ou un autre moyen de réglage de la source de l'adresse ip dans les paquets? Si votre réponse est vrai, il ne répond pas à cette question exacte.
OriginalL'auteur user207421
Pourquoi ne pas vous créer un socket pour chaque interface à la place? Depuis le UDP/IP protocole sans connexion, vous pouvez choisir la source de l'adresse IP en choisissant quel support que vous utilisez pour envoyer la réponse; il n'est pas nécessaire d'utiliser le même socket datagramme entrant est reçu.
Les inconvénients sont que vous ne pouvez plus se lier à l'adresse générique, et vous devez utiliser
select()
,poll()
, plusieurs threads, ou un autre mécanisme pour recevoir des datagrammes provenant de sources multiples en même temps. Vous aurez également besoin d'un peu de logique pour choisir efficacement le support basé sur l'adresse IP du client.Dans la plupart des cas, je pense que l'ajout d'un peu de route des entrées à l'itinéraire de chaque adresse IP distante souhaité à l'adresse IP de l'hôte, et à l'aide d'un socket distinct pour chaque adresse IP de l'hôte et le port de la combinaison, résout les problèmes parfaitement, et le très efficace noyau de la fonctionnalité de le faire. Alors que le comportement peut être une application exigence, je soupçonne que c'est mieux résolu à l'aide de la configuration des interfaces réseau à la place. Malheureusement, souvent, les exigences sont rédigés par des semi-fonctionnelle des idiots mieux adaptés pour le travail manuel, et vos mains sont liées.. si oui, je témoigne de la sympathie.
Si vous avez un réseau de test avec les postes de travail ayant plusieurs interfaces physiques de réseau, je peux fournir un exemple simple C99 programme de test que vous pouvez utiliser pour vérifier les travaux de conception.
Chacune de ces prises séparées peut-être besoin d'être lié à l'une des interfaces fournies et cela ne cesse de changer. Dire 3 premières demandes est allé dehors et a échoué. Maintenant, il y a une liste triée à partir de laquelle je vais choisir les 3 prochaines destinations de chaque de ce qui pourrait être lié à une interface différente. Dans la pratique, ce serveur s'exécute sur une machine qui a environ 10-12 interfaces et pour chaque requête entrante, j'alloue 3 prises qui vivent la vie de cette demande particulière, bien qu'ils auraient à lié à l'une des interfaces au hasard.
Pour ajouter l'insulte à la blessure, c'est de travailler et de fonctionner en production en fait jusqu'à ce que ce regard simple exigence est venu c'est à dire en dehors de tous les 3 requêtes simultanées et de liaison dynamique d'interfaces, si la configuration spécifie une adresse ip de destination: src ip de la liste, d'où votre destination correspond à l'une des entrées de la liste, puis utilisez src ip ip sortants. Donc, il y a une limite à ce que je peux changer dans un système bien développé de production et de test de l'application. Les exigences gars pense que c'est aussi simple que d'appeler une autre liaison avant de relâcher le paquet une fois qu'il est identifié. Autant pour de simples exigences.
Je crois que je comprends. Oui, un typique "simple exigence".. Comme je le vois, le dest-ip:adresse ip source de la liste devrait vraiment être configuré dans la table de routage, au lieu de l'application. De cette façon, votre service se lie à l'adresse générique, et les clients de voir la bonne adresse IP source. Voir
man 8 route
pour plus de détails. La table de routage peut être mis à jour en temps réel, même sous le contrôle de votre demande, si vous le souhaitez. Je ne voudrais pas, cependant.J'ai trouvé les détails de IP_PACKETINFO et sendmsg et ai eu de travail. Veuillez prendre un coup d'oeil au code suivant quand vous le pouvez. Toutes les opinions sont vraiment appréciés. Merci
OriginalL'auteur Nominal Animal