Berkeley Sockets ist eine Anwendungsprogrammierschnittstelle (API) für Internet-Sockets und Unix-Domänensockets, die für die Interprozesskommunikation (IPC) verwendet wird. Sie wird im Allgemeinen als Bibliothek von verknüpfbaren Modulen implementiert. Es wurde mit dem 4.2BSD Unix-Betriebssystem entwickelt, das 1983 veröffentlicht wurde.
Ein Socket ist eine abstrakte Darstellung (Handle) für den lokalen Endpunkt eines Netzwerkkommunikationspfads. Die Berkeley-Sockets-API stellt sie als Dateideskriptor (Dateihandle) in der Unix-Philosophie dar, die eine gemeinsame Schnittstelle für die Eingabe und Ausgabe von Datenströmen bereitstellt.
Berkeley-Sockel entwickelten sich mit einer geringen Modifikation von einem De-facto-Standard zu einem Bestandteil der POSIX-Spezifikation. Daher ist der Begriff POSIX-Sockel im Wesentlichen gleichbedeutend mit Berkeley-Sockel . Sie sind auch als BSD-Sockel bekannt, was die erste Implementierung in der Berkeley Software Distribution bestätigt.
Geschichte und Implementierungen [ edit ]
Berkeley-Sockel wurden mit dem 4.2BSD-Unix-Betriebssystem (1983 veröffentlicht) als Programmierschnittstelle erstellt. Erst 1989 konnte UC Berkeley Versionen seines Betriebssystems und seiner Netzwerkbibliothek von den Lizenzbeschränkungen der proprietären Unix der AT & T Corporation freigeben.
Alle modernen Betriebssysteme implementieren eine Version der Berkeley- oder POSIX-Socket-Schnittstelle. Es wurde zur Standardschnittstelle für die Verbindung zum Internet. Selbst die Winsock-Implementierung für MS Windows, die von unabhängigen Entwicklern entwickelt wurde, folgt dem Standard.
Die BSD-Sockets-API ist in der Programmiersprache C geschrieben. Die meisten anderen Programmiersprachen bieten ähnliche Schnittstellen, die normalerweise als Wrapperbibliothek auf der Basis der C-API geschrieben sind. BSD- und POSIX-Sockets [ edit ]
Als die Berkeley-Socket-API weiterentwickelt wurde und letztendlich ergab die POSIX-Socket-API, [2] wurden bestimmte Funktionen abgelehnt oder entfernt und durch andere ersetzt. Die POSIX-API ist auch als wiedereintrittsfähig konzipiert.
Aktion | BSD | POSIX |
---|---|---|
Konvertierung von Textadresse in gepackte Adresse | inet_aton | inet_pton |
Konvertierung von gepackter Adresse in Textadresse | inet_ntoa | inet_ntop |
Forward-Lookup für Hostnamen / -service | gethostbyname, gethostbyaddr, getservbyname, getservbyport | getaddrinfo |
Reverse-Lookup für Hostnamen / -service | gethostbyaddr, getservbyport | getnameinfo |
Alternativen [ edit ]
Die STREAMS-basierte Transport Layer Interface (TLI) -API bietet eine Alternative zur Socket-API. Viele Systeme, die die TLI-API bereitstellen, bieten jedoch auch die Berkeley-Socket-API.
Nicht-Unix-Systeme machen die Berkeley-Socket-API mit einer Übersetzungsschicht häufig einer nativen Netzwerk-API zugänglich. Plan 9 [3] und Genode [4] verwenden Dateisystem-APIs mit Steuerdateien anstelle von Dateideskriptoren.
Die Berkeley-Socket-Schnittstelle ist in mehreren Header-Dateien definiert. Die Namen und Inhalte dieser Dateien unterscheiden sich geringfügig zwischen den Implementierungen. Im Allgemeinen gehören dazu:
Datei | Beschreibung |
---|---|
sys / socket.h | Core-Socket-Funktionen und Datenstrukturen. |
netinet / in.h | AF_INET und AF_INET6 adressieren Familien und ihre entsprechenden Protokollfamilien, PF_INET und PF_INET6. Dazu gehören Standard-IP-Adressen sowie TCP- und UDP-Portnummern. |
sys / un.h | PF_UNIX- und PF_LOCAL-Adressfamilie. Wird für die lokale Kommunikation zwischen Programmen verwendet, die auf demselben Computer ausgeführt werden. |
arpa / inet.h | Funktionen zum Bearbeiten numerischer IP-Adressen. |
netdb.h | Funktionen zum Übersetzen von Protokollnamen und Hostnamen in numerische Adressen. Durchsucht lokale Daten sowie Namensdienste. |
Socket-API-Funktionen [ edit ]
Die Berkeley-Socket-API stellt normalerweise Folgendes bereit Funktionen:
- socket () erstellt einen neuen Socket eines bestimmten Typs, der durch eine Ganzzahl identifiziert wird, und weist ihm Systemressourcen zu.
- bind () wird normalerweise serverseitig verwendet und wird assoziiert ein Socket mit einer Socket-Adressstruktur, dh einer angegebenen lokalen IP-Adresse und einer Portnummer.
- listen () wird serverseitig verwendet und bewirkt, dass ein gebundener TCP-Socket in den Abhörstatus wechselt.
- connect () wird auf der Clientseite verwendet und weist einem Socket eine freie lokale Portnummer zu. Im Falle eines TCP-Sockets wird versucht, eine neue TCP-Verbindung herzustellen.
- Accept () wird serverseitig verwendet. Er akzeptiert einen eingehenden eingehenden Versuch, eine neue TCP-Verbindung vom Remote-Client zu erstellen, und erstellt einen neuen Socket, der dem Socketadressenpaar dieser Verbindung zugeordnet ist.
- send () recv () sendto () und recvfrom () werden zum Senden und Empfangen von Daten verwendet. Die Standardfunktionen write () und read () können ebenfalls verwendet werden.
- close () bewirkt, dass das System einem Sockel zugewiesene Ressourcen freigibt. Im Falle von TCP wird die Verbindung beendet.
- gethostbyname () und gethostbyaddr () werden verwendet, um Hostnamen und Adressen aufzulösen. Nur IPv4.
- select () wird zum Suspendieren verwendet und wartet darauf, dass eine oder mehrere der bereitgestellten Socketlisten zum Lesen bereit, zum Schreiben bereit sind oder Fehler aufweisen.
- poll () wird verwendet, um den Status einer Steckdose in einem Steckdosensatz zu überprüfen. Das Set kann getestet werden, um festzustellen, ob ein Socket geschrieben oder gelesen werden kann oder ob ein Fehler aufgetreten ist.
- getsockopt () wird verwendet, um den aktuellen Wert einer bestimmten Socketoption für den angegebenen Socket abzurufen. [19659052] setsockopt () wird verwendet, um eine bestimmte Socket-Option für den angegebenen Socket festzulegen.
Socket [ edit ]
Die Funktion Socket () ] erstellt einen Endpunkt für die Kommunikation und gibt einen Dateideskriptor für den Socket zurück. Es verwendet drei Argumente:
- Domäne die die Protokollfamilie des erstellten Sockets angibt. Zum Beispiel:
- AF_INET für das Netzwerkprotokoll IPv4 (nur IPv4)
- AF_INET6 für IPv6 (und in einigen Fällen abwärtskompatibel mit IPv4)
- AF_UNIX für lokale Buchse (unter Verwendung einer Datei )
- Typ einer von:
- SOCK_STREAM (zuverlässiger Stream-orientierter Dienst oder Stream-Sockets)
- SOCK_DGRAM (Datagramm-Service oder Datagram-Sockets)
- SOCK_SEQPACKET (zuverlässiger sequenzierter Paketdienst)
- SOCK_90 (Rohprotokolle auf der Netzwerkschicht)
- Protokoll das das tatsächlich zu verwendende Transportprotokoll angibt. Die häufigsten sind IPPROTO_TCP IPPROTO_SCTP IPPROTO_UDP IPPROTO_DCCP . Diese Protokolle sind in Datei netinet / in.h angegeben. Der Wert 0 kann verwendet werden, um ein Standardprotokoll aus der ausgewählten Domäne und dem ausgewählten Typ auszuwählen.
Die Funktion gibt -1 zurück, wenn ein Fehler aufgetreten ist. Andernfalls wird eine Ganzzahl zurückgegeben, die den neu zugewiesenen Deskriptor darstellt.
bind [ edit ]
bind () assoziiert einen Socket mit einer Adresse. Wenn ein Socket mit socket () erstellt wird, erhält er nur eine Protokollfamilie, jedoch keine Adresse. Diese Zuordnung muss durchgeführt werden, bevor der Socket Verbindungen von anderen Hosts annehmen kann. Die Funktion hat drei Argumente:
- sockfd ein Deskriptor, der den Sockel darstellt
- my_addr ein Zeiger auf eine sockaddr -Struktur, die die zu bindende Adresse darstellt,
- addrlen ein Feld vom Typ socklen_t Angabe der Größe der sockaddr Struktur.
Bind () gibt bei Erfolg 0 zurück und im Fehlerfall -1. Listen [ edit ]
Nachdem ein Socket mit einer Adresse verknüpft wurde, bereitet listen () die Verbindung für eingehende Verbindungen vor. Dies ist jedoch nur für die Stream-orientierten (verbindungsorientierten) Datenmodi erforderlich, d. H. Für Socket-Typen ( SOCK_STREAM SOCK_SEQPACKET ). listen () erfordert zwei Argumente:
- sockfd ein gültiger Socket-Deskriptor.
- Backlog eine Ganzzahl, die die Anzahl der ausstehenden Verbindungen darstellt, die gleichzeitig in eine Warteschlange gestellt werden können. Das Betriebssystem setzt diesem Wert normalerweise eine Obergrenze.
Wenn eine Verbindung akzeptiert wird, wird sie entschlüsselt. Bei Erfolg wird 0 zurückgegeben. Wenn ein Fehler auftritt, wird -1 zurückgegeben.
accept [ edit ]
Wenn eine Anwendung Stream-orientierte Verbindungen von anderen Hosts abhört, wird sie über solche Ereignisse benachrichtigt (vgl. Funktion select ()) und muss sich initialisieren die Verbindung über die Funktion accept () . Es erstellt für jede Verbindung einen neuen Socket und entfernt die Verbindung aus der Warteschlange. Die Funktion hat folgende Argumente:
- sockfd der Deskriptor des Listening-Sockets, für den die Verbindung in die Warteschlange gestellt wird.
- cliaddr ein Zeiger auf eine sockaddr-Struktur, um die Adressinformationen des Clients zu erhalten.
- addrlen a Zeiger auf einen Ort socklen_t der die Größe der an akzept () übergebenen Client-Adressstruktur angibt. Wenn accept () zurückgegeben wird, enthält dieser Speicherort die Größe (in Bytes) der Struktur.
accept () gibt den neuen Socket-Deskriptor für die akzeptierte Verbindung oder den Wert zurück -1 wenn ein Fehler auftritt. Alle weitere Kommunikation mit dem Remote-Host erfolgt nun über diesen neuen Socket.
Datagram-Sockets erfordern keine Verarbeitung durch accept (), da der Empfänger möglicherweise sofort mit dem Abhörsockel auf die Anforderung reagiert.
connect [ edit ]
connect () stellt eine direkte Kommunikationsverbindung zu einem bestimmten Remote-Host her, der über eine durch seine Datei identifizierte Adresse identifiziert wird Deskriptor.
Bei Verwendung eines verbindungsorientierten Protokolls wird eine Verbindung hergestellt. Bestimmte Protokolltypen sind verbindungslos, insbesondere das User Datagram Protocol. In Verbindung mit verbindungslosen Protokollen definiert connect die Remote-Adresse zum Senden und Empfangen von Daten und ermöglicht die Verwendung von Funktionen wie send und recv . In diesen Fällen verhindert die Verbindungsfunktion den Empfang von Datagrammen aus anderen Quellen.
connect () gibt eine Ganzzahl zurück, die den Fehlercode darstellt: 0 steht für Erfolg, während -1 einen Fehler darstellt. In BSD-abgeleiteten Systemen ist der Status eines Socket-Deskriptors historisch undefiniert, wenn der Aufruf von connect fehlschlägt (wie in der Single-Unix-Spezifikation angegeben). Daher sollten tragbare Anwendungen den Socket-Deskriptor sofort schließen und erhalten Sie einen neuen Deskriptor mit socket (), falls der Aufruf von connect () fehlschlägt.
gethostbyname und gethostbyaddr [ edit ]
Die Funktionen gethostbyname () und gethostbyaddr () werden verwendet, um Hostnamen und -adressen im Domain-Name-System oder die anderen Resolver-Mechanismen des lokalen Hosts aufzulösen (z. B. / etc / hosts lookup). Sie geben einen Zeiger auf ein Objekt vom Typ struct hostent zurück, das einen Internetprotokoll-Host beschreibt. Die Funktionen verwenden die folgenden Argumente:
- name gibt den DNS-Namen des Hosts an.
- addr gibt einen Zeiger auf eine struct in_addr an, die die Adresse des Hosts enthält.
- len spezies die Länge in Bytes von addr .
- type gibt den Typ der Adressfamilie (z. B. AF_INET) der Hostadresse an.
Die Funktionen geben im Fehlerfall einen NULL-Zeiger zurück In diesem Fall kann die externe Ganzzahl h_errno überprüft werden, um festzustellen, ob es sich um einen temporären Fehler oder einen ungültigen oder unbekannten Host handelt. Ansonsten wird ein gültiger struct hostent * zurückgegeben.
Diese Funktionen sind nicht unbedingt Bestandteil der BSD-Socket-API, sondern werden häufig in Verbindung mit den API-Funktionen verwendet. Darüber hinaus werden diese Funktionen nun als ältere Schnittstellen zur Abfrage des Domain-Name-Systems betrachtet. Es wurden neue Funktionen definiert, die vollständig protokollunabhängig sind (IPv6 unterstützen). Diese neuen Funktionen sind getaddrinfo () und getnameinfo () und basieren auf einer neuen addrinfo -Datenstruktur.
Protokoll- und Adressfamilien [ edit ]
Die Socket-API ist eine allgemeine Schnittstelle für Unix-Netzwerke und ermöglicht die Verwendung verschiedener Netzwerkprotokolle und Adressierungsarchitekturen.
Die folgende Liste enthält eine Auswahl von Protokollfamilien (denen der standardmäßige symbolische Bezeichner vorangestellt ist), die in einer modernen Linux- oder BSD-Implementierung definiert sind:
Ein Socket für die Kommunikation unter Verwendung einer beliebigen Familie wird mit der Funktion socket ()
erstellt, indem die gewünschte Protokollfamilie ( PF_ - Identifier) als Argument angegeben wird.
Das ursprüngliche Entwurfskonzept der Socket-Schnittstelle unterschied zwischen Protokolltypen (Familien) und den spezifischen Adresstypen, die jeweils verwendet werden können. Es wurde angenommen, dass eine Protokollfamilie mehrere Adresstypen haben kann. Adresstypen wurden durch zusätzliche symbolische Konstanten definiert, wobei das Präfix AF anstelle von PF verwendet wurde. Die AF -IDs sind für alle Datenstrukturen vorgesehen, die sich speziell mit dem Adresstyp und nicht mit der Protokollfamilie befassen. Dieses Konzept der Trennung von Protokoll und Adresstyp hat jedoch keine Implementierungsunterstützung gefunden, und die AF -Konstanten wurden durch die entsprechende Protokollkennung definiert, wobei zwischen AF und unterschieden wurde. PF Konstanten als technisches Argument ohne praktische Konsequenz. In der Tat gibt es viel Verwirrung bei der richtigen Verwendung beider Formen. [6]
Die Spezifikation von POSIX.1—2008 spezifiziert keine PF -Konstanten, sondern nur [19659079] AF -Konstanten [7]
Raw-Sockets [ edit ]
Raw-Sockets bieten eine einfache Schnittstelle, die die Verarbeitung durch den TCP / IP-Stack des Hosts umgeht. Sie ermöglichen die Implementierung von Netzwerkprotokollen im Benutzerraum und helfen beim Debuggen des Protokollstapels. [8] Raw-Sockets werden von einigen Diensten wie ICMP verwendet, die auf der Internet-Schicht des TCP / IP-Modells arbeiten.
Optionen für Sockel [ edit ]
Nachdem Sie einen Sockel erstellt haben, können Sie Optionen festlegen. Einige der häufigsten Optionen sind:
- TCP_NODELAY deaktiviert den Nagle-Algorithmus.
- SO_KEEPALIVE aktiviert periodische 'Liveness'-Pings, sofern vom Betriebssystem unterstützt.
Blocking- und Non-Blocking-Modus edit ]
Berkeley-Sockel können in einem von zwei Modi betrieben werden: Blockieren oder Nicht-Blockieren.
Ein blockierender Socket gibt die Steuerung erst zurück, wenn er einige oder alle für den Vorgang angegebenen Daten gesendet (oder empfangen) hat. Es ist normal, dass ein blockierender Socket nicht alle Daten sendet. Die Anwendung muss den Rückgabewert prüfen, um zu ermitteln, wie viele Bytes gesendet oder empfangen wurden, und Daten, die noch nicht verarbeitet wurden, erneut zu senden. [9] Bei der Verwendung von Blockierungssockeln sollte besonders auf Überkennung () geachtet werden, da sie danach möglicherweise noch blockiert Anzeigen der Lesbarkeit, wenn ein Client während der Verbindungsphase die Verbindung trennt.
Auf der anderen Seite gibt ein nicht blockierender Socket das zurück, was sich im Empfangspuffer befindet, und fährt sofort fort. Wenn sie nicht korrekt geschrieben werden, sind Programme, die nicht blockierende Sockets verwenden, besonders anfällig für Race-Bedingungen, da die Geschwindigkeit der Netzwerkverbindung unterschiedlich ist.
Ein Socket wird normalerweise mit den Funktionen fcntl () oder ioctl () in den Blockierungs- oder Nichtblockierungsmodus gesetzt.
Terminalsockel [ edit ]
Das Betriebssystem gibt die einem Sockel zugewiesenen Ressourcen erst frei, wenn der Sockel geschlossen wird. Dies ist besonders wichtig, wenn der Aufruf von connect fehlschlägt und erneut versucht wird.
Wenn eine Anwendung einen Socket schließt, wird nur die Schnittstelle zum Socket zerstört. Es liegt in der Verantwortung des Kernels, den Socket intern zu zerstören. Manchmal kann ein Socket bis zu 4 Minuten lang auf der Serverseite in einen TIME_WAIT -Zustand eintreten. [10]
Bei Verwendung von von SVR4-Systemen ()
kann Daten verwerfen. Auf diesen Systemen kann die Verwendung von shutdown ()
oder SO_LINGER erforderlich sein, um die Lieferung aller Daten zu gewährleisten. [11]
Client-Server-Beispiel mit TCP [ edit ]
] Das Transmission Control Protocol (TCP) ist ein verbindungsorientiertes Protokoll, das eine Vielzahl von Fehlerkorrektur- und Leistungsfunktionen für die Übertragung von Byte-Streams bietet. Ein Prozess erstellt einen TCP-Socket, indem er die Funktion socket ()
mit den Parametern für die Protokollfamilie ( PF INET PF_INET6 ), den Socket-Modus für Stream, aufruft Sockets ( SOCK_STREAM ) und die IP-Protokollkennung für TCP ( IPPROTO_TCP ).
Server [ edit ]
Das Einrichten eines einfachen TCP-Servers umfasst die folgenden Schritte:
- Erstellen eines TCP-Sockets mit einem Aufruf an
socket ()
. - Binden des Sockets an den Listen-Port mit einem Aufruf an
bind ()
. Bevorbind ()
aufgerufen wird, muss ein Programmierer einesockaddr_in
-Struktur deklarieren, löschen (mitmemset ()
) und sin_family . (AF_INET
), und füllen Sie die Feldersin_port
(der Überwachungsport in der Reihenfolge der Netzwerkbytes). Die Umwandlung einer short int in eine Netzwerk-Bytereihenfolge kann durch Aufrufen der Funktionhtons ()
(host to network short) erfolgen. - Vorbereiten der Socket für das Abhören von Verbindungen (Herstellen einer Verbindung) (Listening Socket), mit einem Aufruf an
listen ()
. - Annehmen eingehender Verbindungen über einen Anruf an
accept ()
. Dies blockiert, bis eine eingehende Verbindung empfangen wird, und gibt dann einen Socket-Deskriptor für die akzeptierte Verbindung zurück. Der anfängliche Deskriptor bleibt ein hörender Deskriptor, undaccept ()
kann jederzeit wieder mit diesem Socket aufgerufen werden, bis er geschlossen wird. - Kommunikation mit dem entfernten Host, was durch
erfolgen kann ] send ()
undrecv ()
oderwrite ()
undread ()
. - Eventuelles Schließen jedes einmal geöffneten Sockels Es wird nicht mehr benötigt, indem
close ()
.
verwendet wird. Das folgende Programm erstellt einen TCP-Server an Portnummer 1100:
#include #include #include #include #include #include #include #include int main (void) { struct sockaddr_in sa; int SocketFD = Socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); if (SocketFD == -1) { perror ("kann Socket nicht erstellen"); exit (EXIT_FAILURE); } Memset (& sa, 0, sizeof sa); sa.sin_family = AF_INET; sa.sin_port = htons (1100); sa.sin_addr.s_addr = htonl (INADDR_ANY); if (bind (SocketFD, (struct sockaddr *) & sa, sizeof sa) == -1) { perror ("bind failed"); close (SocketFD); exit (EXIT_FAILURE); } if (listen (SocketFD, 10) == -1) { perror ("hören fehlgeschlagen"); close (SocketFD); exit (EXIT_FAILURE); } zum (;;) { int ConnectFD = akzeptieren (SocketFD, NULL, NULL); if (0> ConnectFD) { perror ("Accept failed"); close (SocketFD); exit (EXIT_FAILURE); } / * Leseoperationen ausführen ... lesen (ConnectFD, Buff, Größe) * / if (Herunterfahren (ConnectFD, SHUT_RDWR) == -1) { perror ("Herunterfahren fehlgeschlagen"); schließen (ConnectFD); close (SocketFD); exit (EXIT_FAILURE); } schließen (ConnectFD); } close (SocketFD); return EXIT_SUCCESS; }
Client [ edit ]
Das Programmieren einer TCP-Client-Anwendung umfasst die folgenden Schritte:
- Erstellen eines TCP-Sockets mit einem Aufruf an
socket ()
. - Herstellen einer Verbindung zum Server mithilfe von
connect ()
und Übergeben einessockaddr_in
Struktur mit dersin_family
die auf AF_INETeingestellt ist, sin_port
auf den Port eingestellt, auf den der Endpunkt hört (in Bytereihenfolge) undsin_addr
auf die IP-Adresse des zuhörenden Servers gesetzt (auch in Bytereihenfolge im Netzwerk.) - Kommunikation mit dem Server unter Verwendung von
send ()
undrecv ()
oder] write ()
undread ()
. - Beenden der Verbindung und Aufräumen mit einem Aufruf an
close ()
.
#include #include #include #include #include #include #include #include int main (void) { struct sockaddr_in sa; int res; int SocketFD; SocketFD = Socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); if (SocketFD == -1) { perror ("kann Socket nicht erstellen"); exit (EXIT_FAILURE); } Memset (& sa, 0, sizeof sa); sa.sin_family = AF_INET; sa.sin_port = htons (1100); res = inet_pton (AF_INET, "192.168.1.3", & sa.sin_addr); if (connect (SocketFD, (struct sockaddr *) & sa, sizeof sa) == -1) { perror ("Verbindung fehlgeschlagen"); close (SocketFD); exit (EXIT_FAILURE); } / * Leseoperationen ausführen ... * / Herunterfahren (SocketFD, SHUT_RDWR); close (SocketFD); return EXIT_SUCCESS; }
Client-Server-Beispiel unter Verwendung von UDP [ edit ]
Das User Datagram Protocol (UDP) ist ein verbindungsloses Protokoll ohne Gewährleistung der Zustellung. UDP-Pakete können mehrmals oder gar nicht in der richtigen Reihenfolge eintreffen. Aufgrund dieses minimalen Designs hat UDP einen erheblich geringeren Overhead als TCP. Verbindungslos zu sein bedeutet, dass zwischen zwei Hosts kein Konzept für einen Stream oder eine permanente Verbindung besteht. Solche Daten werden als Datagramme (Datagram Sockets) bezeichnet.
Der UDP-Adressraum, der Bereich der UDP-Port-Nummern (in der ISO-Terminologie die TSAPs), ist völlig unabhängig von dem der TCP-Ports.
Server [ edit ]
Eine Anwendung kann einen UDP-Server an Portnummer 7654 wie folgt einrichten. Das Programm enthält eine Endlosschleife, die UDP-Datagramme mit recvfrom ()
empfängt.
#include #include #include #include #include #include #include / * für close () für Socket * / #include int main (void) { int socke; struct sockaddr_in sa; Zeichenpuffer [1024]; ssize_t recsize; socklen_t fromlen; Memset (& sa, 0, sizeof sa); sa.sin_family = AF_INET; sa.sin_addr.s_addr = htonl (INADDR_ANY); sa.sin_port = htons (7654); fromlen = sizeof sa; Socke = Socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (bind (sock, (struct sockaddr *) & sa, sizeof sa) == -1) { perror ("Fehlerbindung fehlgeschlagen"); Schließen (Socke); exit (EXIT_FAILURE); } zum (;;) { recsize = recvfrom (sock, (void *) Puffer, sizeof buffer, 0, (struct sockaddr *) & sa, & fromlen); if (recsize <0) { fprintf (stderr, "% s n", strerror (errno)); exit (EXIT_FAILURE); } printf ("recsize:% d n", (int) recsize); Schlaf (1); printf ("datagram:%. * s n", (int) recsize, buffer); } }
Client [ edit ]
Ein einfaches Client-Programm zum Senden eines UDP-Pakets mit der Zeichenfolge "Hello World!" Die Adresse 127.0.0.1 und die Portnummer 7654 können folgendermaßen aussehen:
#include #include #include #include #include #include #include #include #include int main (void) { int socke; struct sockaddr_in sa; int bytes_sent; Zeichenpuffer [200]; strcpy (Puffer, "Hallo Welt!"); / * Internet, Datagramm, Socket mit UDP erstellen * / Socke = Socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (Socke == -1) { / * Wenn Socket nicht initialisiert werden konnte, beenden Sie * / printf ("Fehler beim Erstellen des Socket"); exit (EXIT_FAILURE); } / * Nullsockeladresse * / Memset (& sa, 0, sizeof sa); / * Die Adresse lautet IPv4 * / sa.sin_family = AF_INET; / * IPv4-Adressen ist ein uint32_t, konvertiert eine Zeichenfolgendarstellung der Oktette in den entsprechenden Wert * / sa.sin_addr.s_addr = inet_addr ("127.0.0.1"); / * Sockets sind unsignierte Kurzschlüsse, htons (x) stellt sicher, dass x in der Bytereihenfolge des Netzwerks ist, setzen Sie den Port auf 7654 * / sa.sin_port = htons (7654); bytes_sent = sendto (socke, puffer, strlen (puffer), 0, (struct sockaddr *) & sa, sizeof sa); if (bytes_sent <0) { printf ("Fehler beim Senden des Pakets:% s n", strerror (errno)); exit (EXIT_FAILURE); } Schließen (Socke); / * die Steckdose schließen * / 0 zurückgeben; }
In diesem Code ist buffer ein Zeiger auf die zu sendenden Daten, und buffer_length gibt die Größe der Daten an.
Caveats [ edit ]
Bei TCP-Verbindungen muss das Betriebssystem die ihm mit einem write ()
-Aufruf angegebenen Daten erneut übertragen. Das Benutzerraumprogramm kann jedoch den an write ()
übergebenen Datenpuffer nach write ()
zurücksetzen. Dies bedeutet, dass das Betriebssystem eine Kopie der Daten erstellen muss, was in Anwendungen mit hohem Durchsatz und hoher Leistung zu einer erheblichen CPU-Belastung führen kann. Andere APIs, z. B. die RDMA-Unterstützung, setzen voraus, dass der Datenpuffer erst freigegeben wird, wenn die Bestätigung von der Gegenseite empfangen wurde. Dadurch können Kopiervorgänge ohne Arbeitsspeicher ausgeführt werden.
Referenzen [ edit ]
Die de jure Standarddefinition der Sockets-Schnittstelle ist im POSIX-Standard enthalten, bekannt als:
- IEEE Std. 1003.1-2001 Standard für Informationstechnologie - Schnittstelle für tragbare Betriebssysteme (POSIX).
- Offener technischer Konzernstandard: Basisspezifikationen, Ausgabe 6, Dezember 2001.
- ISO / IEC 9945: 2002
Informationen zu dieser Norm und laufende Arbeiten sind auf der Austin-Website verfügbar.
Die IPv6-Erweiterungen der Basis-Socket-API sind in RFC 3493 und RFC 3542 dokumentiert.
Externe Links [ edit ]
Dieser Artikel basiert auf Material aus dem Free Online Dictionary of Computing von vor 1. November 2008 und unter den "relicensing" -Bestimmungen der GFDL, Version 1.3 oder höher, aufgenommen.
No comments:
Post a Comment