Automatisierte Benennung von AF_UNIX lokalen Datagramm-Sockets?
Frage
Ich bin die Implementierung einer einfachen Service-Datagramme über Unix lokale Steckdosen (AF_UNIX Adresse der Familie, das heißt nicht UDP ) verwenden. Der Server ist mit einer öffentlichen Adresse gebunden, und es empfängt Anforderungen gut. Leider, wenn es um die Beantwortung zurückkommt, versagt sendto
es sei denn, der Kunde zu gebunden ist. (Der gemeinsame Fehler ist Transport endpoint is not connected
).
Die Bindung an einen zufälligen Namen (Dateisystem-basierte oder abstrakt) arbeitet. Aber ich möchte, dass vermeiden: Wer bin ich die Namen zu gewährleisten, nahm ich nicht kollidieren
Der Modus Dokumentation Unix-Sockets-Stream sagen uns, dass ein abstrakter Name in connect
Zeit zu ihnen zugewiesen wird, wenn sie eine noch nicht haben. Ist ein solches Feature für Datagramm orientierte Steckdosen?
Lösung
Ich gehe davon aus, dass Sie Linux laufen; Ich weiß nicht, ob dieser Rat zu SunOS oder jede UNIX gilt.
Zuerst die Antwort: Nach der Buchse () und vor dem connect () oder erste sendto (), versuchen Sie diesen Code hinzu:
struct sockaddr_un me;
me.sun_family = AF_UNIX;
int result = bind(fd, (void*)&me, sizeof(short));
Nun wird die Erklärung: die der Unix (7) Manpage dies sagt:
Wenn eine Steckdose angeschlossen ist und nicht bereits eine lokale Adresse einer eindeutige Adresse in der Zusammenfassung Namensraum wird generiert automatisch.
Leider liegt die Mann-Seite.
Die Untersuchung des Linux-Quellcode , sehen wir, dass unix_dgram_connect () nur Anrufe unix_autobind (), wenn SOCK_PASSCRED in den Sockel Flags gesetzt ist. Da ich nicht weiß, was SOCK_PASSCRED ist, und es ist jetzt 01.00 Uhr, muss ich für eine andere Lösung suchen.
unix_bind , ich bemerke, dass unix_bind Anrufe unix_autobind wenn der übergebene Größe gleich „sizeof (kurz)“. Somit wird die Lösung über.
Viel Glück und guten Morgen.
Rob
Andere Tipps
Die Unix (7) Manpage I verwiesen hatte diese Informationen über autobind UNIX-Sockets :
Wenn ein bind (2) Aufruf gibt addrlen als sizeof (sa_family_t) oder die SO_PASSCRED Socket-Option wurde für einen Socket angegeben, die nicht explizit an eine Adresse gebunden wurde, dann ist die Buchse auf eine abstrakte Adresse autobound wird.
Aus diesem Grund ist der Linux-Kernel die Adresse Länge gleich sizeof (short) überprüft, weil sa_family_t ein kurz ist. Die andere Unix (7) man-Seite von Robs große Antwort verwiesen sagt, dass Client-Sockets werden immer auf connect autobound, sondern weil SOCK_DGRAM Steckdosen verbindungslos sind (trotz sie auffordern verbinden) Ich glaube, dies gilt nur für SOCK_STREAM Sockets.
Beachten Sie auch, dass, wenn Sie Ihre eigenen abstrakten Namespace Socket-Namen liefern, die Adresse der Buchse in diesem Namensraum durch die zusätzlichen Bytes in sun_path gegeben wird, die durch die angegebene Länge der Adressstruktur abgedeckt ist.
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 () soll ebenfalls die Adressenlänge begrenzen, und übergibt sizeof nicht (sockaddr_un).
Ein bisschen eine späte Antwort, aber für wen auch immer findet diese Google verwenden wie ich. Rob Adams Antwort hat mir geholfen, die ‚echte‘ Antwort auf diese Frage zu bekommen. Verwenden Sie einfach eingestellt (Stufe SO_SOCKET
siehe man 7 unix
) SO_PASSCRED
1. Keine Notwendigkeit für eine dumme binden setzen
Ich habe diese in PHP, aber es hat nicht SO_PASSCRED
definiert (dumm PHP). Es funktioniert immer noch, obwohl, wenn Sie es selbst zu definieren. Auf meinem Computer hat es den Wert von 16, und ich rechne damit, dass es recht portabel funktioniert.
Ich bin mir nicht so sicher, ob ich verstehe Ihre Frage vollständig, aber hier ist ein Datagramm Implementierung eines Echo-Server ich gerade schrieb. Sie können sehen, der Server an den Client auf dem gleichen IP / PORT reagiert es aus gesendet wurde.
Hier ist der Code
Zuerst wird der Server (Hörer)
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()
Und nun der Kunde (Absender), die die Antwort der Zuhörer
empfängtfrom 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