Domanda

Sto implementando un servizio semplice, utilizzando i datagrammi su unix locale prese (AF_UNIX indirizzo di famiglia, vale a dire non UDP).Il server a cui è associato un indirizzo pubblico, e riceve le richieste di bene.Purtroppo, quando si tratta di rispondere indietro, sendto non riesce a meno che il cliente è tenuto, troppo.(l'errore comune è Transport endpoint is not connected).

Associazione a qualche nome a caso (filesystem basato su o astratto) funziona.Ma vorrei evitare che:chi sono io per garantire i nomi che ho scelto non si scontrano?

Il socket unix " stream modalità di documentazione ci dicono che in astratto il nome a loro assegnato a connect ora, se non ne hai già uno.È una funzione disponibile per datagramma orientato prese?

È stato utile?

Soluzione

Mi si supponga che si esegue Linux;Non so se questo consiglio si applica a SunOS o UNIX.

Primo, la risposta:dopo il socket() e prima di connect() o prima sendto(), prova ad aggiungere questo codice:

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

Ora, la spiegazione:il unix(7) pagina man dice questo:

Quando un socket è connesso e non dispone già di un indirizzo locale un indirizzo univoco in astratto spazio dei nomi verrà generato automaticamente.

Purtroppo, l'uomo che pagina si trova.

Esaminando il Il codice sorgente di Linux, vediamo che unix_dgram_connect() solo chiamate unix_autobind() se SOCK_PASSCRED è situato nella presa bandiere.Dal momento che non so cosa SOCK_PASSCRED è, ed è ora 1:00 di notte, ho bisogno di cercare un'altra soluzione.

L'esame unix_bind, Mi accorgo che unix_bind chiamate unix_autobind se in passato la dimensione è uguale a "sizeof(short)".Così, la soluzione di cui sopra.

Buona fortuna, e buon giorno.

Rob

Altri suggerimenti

Il unix(7) pagina man ho riferito questa informazioni su autobind socket UNIX:

Se un bind(2) chiamata specifica addrlen come sizeof(sa_family_t), o il SO_PASSCRED presa è stata specificata l'opzione per un socket che non è stato esplicitamente associato a un indirizzo, quindi il socket è autobound di un abstract indirizzo.

Questo è il motivo per cui il kernel di Linux controlla l'indirizzo di lunghezza pari a sizeof(short) perché sa_family_t è breve.Altri unix pagina man(7) a cui fa riferimento Rob grande risposta dice che i socket client sono sempre autobound su connetti, ma perché SOCK_DGRAM prese sono di tipo connectionless (nonostante chiamata connect su di loro) credo che questo vale solo per SOCK_STREAM.

Nota anche che quando fornire il proprio spazio dei nomi astratti presa di nomi, la presa di indirizzo in questo spazio dei nomi è dato dal byte aggiuntivi in sun_path che sono coperti dalla lunghezza specificata la struttura di un indirizzo.

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() dovrebbe anche limitare l'indirizzo di lunghezza, e non passare sizeof(sockaddr_un).

Un po ' di una risposta tardiva, ma per chi trova questo utilizzando google come ho fatto io.Rob Adamo e la sua risposta mi ha aiutato a ottenere la "vera" risposta a questo:semplicemente usare insieme (livello SO_SOCKET, vedere man 7 unix) per impostare SO_PASSCRED 1.Nessun bisogno di una stupida bind.

Ho usato questo in PHP, ma non hanno SO_PASSCRED definito (stupido PHP).Lo fa ancora, anche se, se si definiscono da soli.Sul mio computer non ha il valore di 16 anni, e mi sa che sarà un lavoro molto portabile.

Io non sono così sicuro di aver capito la tua domanda completamente, ma qui è un datagramma implementazione di un server di eco ho appena scritto.Si può vedere il server risponde al client sullo stesso IP/PORTA è stato inviato dall'.

Ecco il codice

Primo, il server (listener)

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

E ora, il Cliente (mittente) che riceve la risposta da parte dell'Ascoltatore

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top