Automatizzato di denominazione di PREAVVISO locale datagram socket?
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?
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