Angenommen, der abhörende Socket, der an accept
hat nicht standardmäßige Optionen, die mit setsockopt
. Werden diese Optionen (einige oder alle?) an die resultierenden Dateideskriptoren für akzeptierte Verbindungen vererbt?
Antworten
Zu viele Anzeigen?Mehrere der Steckdosenoptionen werden auf niedrigeren Ebenen des Systems behandelt. Während die meisten Socket-Optionen mit dem Befehl setsockopt gesetzt werden können. Referenz: man setsockopt
Und da Sie nur POSIX auf jedem Linux im Allgemeinen als Ihren Anwendungsbereich erwähnen. Die accept()
(Referenz: man accept
) hat einen gewissen Ermessensspielraum, welche Socket-Optionen geerbt werden sollen und welche Optionen von der lauschenden fd zurückgewiesen werden sollen.
accept() verändert den ursprünglichen Socket, der als Argument übergeben wurde, nicht. Der neue Socket, der von accept() zurückgegeben wird, erbt keine Dateistatusflags wie O_NONBLOCK, O_ASYNC vom hörenden Socket.
Anstatt sich also auf die Vererbung oder Nichtvererbung der Eigenschaften des abhörenden Sockets zu verlassen (die zwangsläufig je nach Implementierung und Lizenz variieren), sollte der akzeptierte Socket explizit mit den gewünschten Socket-Optionen festgelegt werden (Best Practice).
Manpages und die Implementierungscodes auf Ihrem Rechner sind die relevantesten Spezifikationen für das accept()-Verhalten, da es keine gemeinsame oder standardisierte Spezifikation für mehrere Linux-Varianten gibt.
Nein, sie werden nicht unbedingt vererbt. Probieren Sie dieses Beispiel, das die Größe des Empfangspuffers festlegt ( SO_RCVBUF
) auf dem ursprünglichen Socket auf einen Nicht-Standardwert und vergleicht dann das Ergebnis mit dem geerbten Socket. Führen Sie diesen Code aus, der auf dem TCP-Port 12345 lauscht, und stellen Sie dann von einem beliebigen anderen Programm aus eine Verbindung zu ihm her.
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
void die(const char *f)
{
printf("%s: %s\n", f, strerror(errno));
exit(1);
}
int main(void)
{
int s = socket(AF_INET, SOCK_STREAM, 0);
if(s < 0)
die("socket");
int rcvbuf;
socklen_t optlen = sizeof(rcvbuf);
if(getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &optlen) < 0)
die("getsockopt (1)");
printf("initial rcvbuf: %d\n", rcvbuf);
rcvbuf *= 2;
if(setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) < 0)
die("setsockopt");
printf("set rcvbuf to %d\n", rcvbuf);
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(12345);
sin.sin_addr.s_addr = INADDR_ANY;
if(bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
die("bind");
if(listen(s, 10) < 0)
die("listen");
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
int s2 = accept(s, (struct sockaddr *)&client_addr, &addr_len);
if(s2 < 0)
die("accept");
printf("accepted connection\n");
optlen = sizeof(rcvbuf);
if(getsockopt(s2, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &optlen) < 0)
die("getsockopt (2)");
printf("new rcvbuf: %d\n", rcvbuf);
return 0;
}
Ergebnis auf einem Rechner mit Linux 3.0.0-21-generic:
initial rcvbuf: 87380
set rcvbuf to 174760
accepted connection
new rcvbuf: 262142
Die Steckdosenoptionen sind der Ort, an dem Dinge untergebracht werden, die anderswo keinen Platz finden. Es wird also erwartet, dass verschiedene Socket-Optionen ein unterschiedliches Vererbungsverhalten haben. Ob eine Socket-Option vererbt werden soll oder nicht, wird von Fall zu Fall entschieden.
Die Antwort lautet Nein für POSIX-konforme Implementierungen, so wie ich es verstanden habe.
Aus der POSIX-2017-Spezifikation für accept():
Die Funktion accept() extrahiert die erste Verbindung aus der Warteschlange der anstehenden Verbindungen, erstellt einen neuen Socket mit dem gleichen Socket-Typ-Protokoll und der gleichen Adressfamilie wie der angegebene Socket und weist einen neuen Dateideskriptor für diesen Socket zu.
Beachten Sie, dass es sich explizit um einen "neuen Socket" handelt und nicht um eine "vollständige oder teilweise Kopie des Sockets, der aus der Warteschlange genommen wird", so dass keine anderen Optionen als die Standardoptionen für diesen Socket-Typ und diese Adressfamilie zur Verfügung stehen sollten. Während das Kopierverhalten wünschenswert sein kann, wird dies als eine Erweiterungsschnittstelle belassen, die eine Plattform haben kann. Ich habe jedoch nicht gesehen, dass irgendeine Plattform eine solche Schnittstelle implementiert, so dass sie in den Standard aufgenommen werden könnte. Es liegt daher in der Verantwortung der Anwendung, mit getsockopt()/setsockopt() alle von den Standardwerten abweichenden Attribute vom Queue-Socket in den zurückgegebenen Socket zu kopieren, was nicht in der Verantwortung der Schnittstelle liegt, bevor dieser Socket zum Senden oder Empfangen von Daten verwendet wird.