Question

J'implémente un service simple utilisant des datagrammes sur des sockets locales unix (famille d'adresses AF_UNIX, c'est-à-dire pas UDP ). Le serveur est lié à une adresse publique et il reçoit très bien les demandes. Malheureusement, en ce qui concerne la réponse, sendto échoue sauf si le client est également lié. (L'erreur commune est Le noeud final de transport n'est pas connecté ).

La liaison à un nom aléatoire (basé sur un système de fichiers ou abstraite) fonctionne. Mais j'aimerais éviter cela: qui dois-je garantir que les noms que j'ai choisis ne seront pas en collision?

La documentation en mode flux des sockets unix nous indique qu’un nom abstrait leur sera attribué à l’heure connect s’ils n’en ont pas déjà. Une telle fonctionnalité est-elle disponible pour les sockets orientés datagramme?

Était-ce utile?

La solution

Je suppose que vous utilisez Linux; Je ne sais pas si ce conseil s’applique à SunOS ou à UNIX.

Tout d’abord, la réponse: après le socket () et avant le connect () ou le premier sendto (), essayez d’ajouter ce code:

struct sockaddr_un me;
me.sun_family = AF_UNIX;
int result = bind(fd, (void*)&me, sizeof(short));

Maintenant, l'explication: la unix (7) . dit ceci:

  

Quand un socket est connecté et qu'il   n’a pas déjà d’adresse locale un   adresse unique dans le résumé   l'espace de noms sera généré   automatiquement.

Malheureusement, la page de manuel est mensongère.

Examen du code source Linux , nous voyons que unix_dgram_connect () appelle uniquement unix_autobind () si SOCK_PASSCRED est défini dans les indicateurs de socket. Comme je ne sais pas ce que SOCK_PASSCRED est et qu'il est maintenant 1 h, je dois rechercher une autre solution.

Examen de unix_bind , Je remarque que unix_bind appelle unix_autobind si la taille transmise est égale à "sizeof (short)". Ainsi, la solution ci-dessus.

Bonne chance et bonjour.

Rob

Autres conseils

La page de manuel unix (7) que j'ai référencée contient des informations sur les sockets UNIX Autobind. :

  

Si un appel bind (2) spécifie addrlen comme sizeof (sa_family_t) ou si l'option de socket SO_PASSCRED est spécifiée pour une socket qui n'est pas explicitement liée à une adresse, elle est automatiquement liée à une adresse abstraite.

C'est pourquoi le noyau Linux vérifie que la longueur de l'adresse est égale à sizeof (short) car sa_family_t est un short. L'autre page de manuel unix (7) référencée par l'excellente réponse de Rob indique que les sockets client sont toujours autobound sur connect, mais parce que les sockets SOCK_DGRAM sont sans connexion (malgré l'appel, connect), je pense que cela ne s'applique qu'aux sockets SOCK_STREAM.

Notez également que lorsque vous fournissez vos propres noms de socket d’espace de noms abstrait, l’adresse du socket dans cet espace de noms est donnée par les octets supplémentaires de sun_path couverts par la longueur spécifiée de la structure d’adresse.

struct sockaddr_un me;
const char name[] = "\0myabstractsocket";
me.sun_family = AF_UNIX;
// size-1 because abstract socket names are not null terminated
memcpy(me.sun_path, name, sizeof(name) - 1);
int result = bind(fd, (void*)&me, sizeof(me.sun_family) + sizeof(name) - 1);

sendto () devrait également limiter la longueur de l'adresse et ne pas passer à sizeof (sockaddr_un).

Réponse un peu tardive, mais à quiconque le trouvera en utilisant Google comme je l’ai fait. La réponse de Rob Adam m'a aidé à obtenir la réponse "réelle" à cette question: utilisez simplement set (niveau SO_SOCKET , voir man 7 unix ) pour définir SO_PASSCRED . à 1. Pas besoin d'un lien stupide.

Je l'ai utilisé en PHP, mais SO_PASSCRED n'est pas défini (PHP stupide). Cela fonctionne quand même si vous le définissez vous-même. Sur mon ordinateur, la valeur est 16 et je pense que cela fonctionnera de manière très portable.

Je ne suis pas sûr de bien comprendre votre question, mais voici une implémentation datagramme d'un serveur d'écho que je viens d'écrire. Vous pouvez voir que le serveur répond au client sur le même IP / PORT qu’il a été envoyé.

Voici le code

Tout d'abord, le serveur (écouteur)

from socket import *
import time
class Listener:
    def __init__(self, port):
        self.port = port
        self.buffer = 102400

    def listen(self):

        sock = socket(AF_INET, SOCK_DGRAM)
        sock.bind(('', self.port))

        while 1:
            data, addr = sock.recvfrom(self.buffer)
            print "Received: " + data
            print "sending to %s" % addr[0]
            print "sending data %s" % data
            time.sleep(0.25)
            #print addr # will tell you what IP address the request came from and port
            sock.sendto(data, (addr[0], addr[1]))
            print "sent"
        sock.close()

if __name__ == "__main__":
    l = Listener(1975)
    l.listen()

Et maintenant, le client (expéditeur) qui reçoit la réponse de l'auditeur

from socket import *
from time import sleep
class Sender:
    def __init__(self, server):
       self.port = 1975
       self.server = server
       self.buffer = 102400

    def sendPacket(self, packet):
        sock = socket(AF_INET, SOCK_DGRAM)
        sock.settimeout(10.75)


        sock.sendto(packet, (self.server, int(self.port)))

        while 1:
            print "waiting for response"
            data, addr = sock.recvfrom(self.buffer)
            sock.close()
            return data



if __name__ == "__main__":
        s = Sender("127.0.0.1")
        response = s.sendPacket("Hello, world!")
        print response
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top