Unix Socket - Kernfunktionen
In diesem Kapitel werden die wichtigsten Socket-Funktionen beschrieben, die zum Schreiben eines vollständigen TCP-Clients und -Servers erforderlich sind.
Das folgende Diagramm zeigt die vollständige Client- und Server-Interaktion -
Die Socket-Funktion
Um eine Netzwerk-E / A durchzuführen, muss ein Prozess zunächst die Socket-Funktion aufrufen und den Typ des gewünschten Kommunikationsprotokolls und die Protokollfamilie usw. angeben.
#include <sys/types.h>
#include <sys/socket.h>
int socket (int family, int type, int protocol);
Dieser Aufruf gibt einen Socket-Deskriptor zurück, den Sie in späteren Systemaufrufen verwenden können, oder -1 bei einem Fehler.
Parameter
family - Es gibt die Protokollfamilie an und ist eine der unten gezeigten Konstanten. -
Familie | Beschreibung |
---|---|
AF_INET | IPv4-Protokolle |
AF_INET6 | IPv6-Protokolle |
AF_LOCAL | Unix-Domänenprotokolle |
AF_ROUTE | Routing-Sockets |
AF_KEY | Ket Steckdose |
Dieses Kapitel behandelt keine anderen Protokolle als IPv4.
type- Es gibt die Art der gewünschten Steckdose an. Es kann einen der folgenden Werte annehmen -
Art | Beschreibung |
---|---|
SOCK_STREAM | Stream-Socket |
SOCK_DGRAM | Datagramm-Socket |
SOCK_SEQPACKET | Sequenzierter Paketsocket |
SOCK_RAW | Roher Sockel |
protocol - Das Argument sollte auf den unten angegebenen Protokolltyp oder auf 0 gesetzt werden, um den Standard des Systems für die angegebene Kombination aus Familie und Typ auszuwählen. -
Protokoll | Beschreibung |
---|---|
IPPROTO_TCP | TCP-Transportprotokoll |
IPPROTO_UDP | UDP-Transportprotokoll |
IPPROTO_SCTP | SCTP-Transportprotokoll |
Die Connect - Funktion
Die Verbindungsfunktion wird von einem TCP-Client verwendet, um eine Verbindung mit einem TCP-Server herzustellen.
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
Dieser Aufruf gibt 0 zurück, wenn eine erfolgreiche Verbindung zum Server hergestellt wurde, andernfalls wird bei einem Fehler -1 zurückgegeben.
Parameter
sockfd - Es ist ein Socket-Deskriptor, der von der Socket-Funktion zurückgegeben wird.
serv_addr - Es ist ein Zeiger auf struct sockaddr, der die Ziel-IP-Adresse und den Port enthält.
addrlen - Stellen Sie es auf sizeof (struct sockaddr) ein.
Die bind - Funktion
Die Bindefunktion weist einem Socket eine lokale Protokolladresse zu. Bei den Internetprotokollen ist die Protokolladresse die Kombination aus einer 32-Bit-IPv4-Adresse oder einer 128-Bit-IPv6-Adresse sowie einer 16-Bit-TCP- oder UDP-Portnummer. Diese Funktion wird nur vom TCP-Server aufgerufen.
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr,int addrlen);
Dieser Aufruf gibt 0 zurück, wenn er erfolgreich an die Adresse gebunden wurde, andernfalls wird bei einem Fehler -1 zurückgegeben.
Parameter
sockfd - Es ist ein Socket-Deskriptor, der von der Socket-Funktion zurückgegeben wird.
my_addr - Es ist ein Zeiger auf struct sockaddr, der die lokale IP-Adresse und den Port enthält.
addrlen - Stellen Sie es auf sizeof (struct sockaddr) ein.
Sie können Ihre IP-Adresse und Ihren Port automatisch eingeben
Ein 0-Wert für die Portnummer bedeutet, dass das System einen zufälligen Port auswählt , und ein INADDR_ANY- Wert für die IP-Adresse bedeutet, dass die IP-Adresse des Servers automatisch zugewiesen wird.
server.sin_port = 0;
server.sin_addr.s_addr = INADDR_ANY;
NOTE- Alle Ports unter 1024 sind reserviert. Sie können einen Port über 1024 und unter 65535 festlegen, es sei denn, diese werden von anderen Programmen verwendet.
Die Listen- Funktion
Die Listen- Funktion wird nur von einem TCP-Server aufgerufen und führt zwei Aktionen aus:
Die Listen-Funktion konvertiert einen nicht verbundenen Socket in einen passiven Socket und gibt an, dass der Kernel eingehende Verbindungsanforderungen akzeptieren soll, die an diesen Socket gerichtet sind.
Das zweite Argument für diese Funktion gibt die maximale Anzahl von Verbindungen an, die der Kernel für diesen Socket in die Warteschlange stellen soll.
#include <sys/types.h>
#include <sys/socket.h>
int listen(int sockfd,int backlog);
Dieser Aufruf gibt bei Erfolg 0 zurück, andernfalls gibt er bei Fehler -1 zurück.
Parameter
sockfd - Es ist ein Socket-Deskriptor, der von der Socket-Funktion zurückgegeben wird.
backlog - Dies ist die Anzahl der zulässigen Verbindungen.
Die akzeptieren Funktion
Die Akzeptanzfunktion wird von einem TCP-Server aufgerufen, um die nächste abgeschlossene Verbindung von der Vorderseite der Warteschlange für abgeschlossene Verbindungen zurückzugeben. Die Signatur des Anrufs lautet wie folgt:
#include <sys/types.h>
#include <sys/socket.h>
int accept (int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
Dieser Aufruf gibt bei Erfolg einen nicht negativen Deskriptor zurück, andernfalls wird bei einem Fehler -1 zurückgegeben. Es wird angenommen, dass der zurückgegebene Deskriptor ein Client-Socket-Deskriptor ist, und alle Lese- / Schreibvorgänge werden an diesem Deskriptor ausgeführt, um mit dem Client zu kommunizieren.
Parameter
sockfd - Es ist ein Socket-Deskriptor, der von der Socket-Funktion zurückgegeben wird.
cliaddr - Es ist ein Zeiger auf struct sockaddr, der die Client-IP-Adresse und den Port enthält.
addrlen - Stellen Sie es auf sizeof (struct sockaddr) ein.
Die Sendefunktion
Die Sendefunktion wird verwendet , um Daten über Stream - Sockets oder CONNECTED Datagramm - Sockets zu senden. Wenn Sie Daten über UNCONNECTED-Datagramm-Sockets senden möchten, müssen Sie die Funktion sendto () verwenden.
Sie können den Systemaufruf write () verwenden, um Daten zu senden. Die Unterschrift lautet wie folgt:
int send(int sockfd, const void *msg, int len, int flags);
Dieser Aufruf gibt die Anzahl der gesendeten Bytes zurück, andernfalls wird bei einem Fehler -1 zurückgegeben.
Parameter
sockfd - Es ist ein Socket-Deskriptor, der von der Socket-Funktion zurückgegeben wird.
msg - Es ist ein Zeiger auf die Daten, die Sie senden möchten.
len - Dies ist die Länge der Daten, die Sie senden möchten (in Bytes).
flags - Es wird auf 0 gesetzt.
Die Recv- Funktion
Die Recv- Funktion wird verwendet, um Daten über Stream-Sockets oder CONNECTED-Datagramm-Sockets zu empfangen. Wenn Sie Daten über UNCONNECTED-Datagramm-Sockets empfangen möchten, müssen Sie recvfrom () verwenden.
Sie können den Systemaufruf read () verwenden, um die Daten zu lesen. Dieser Aufruf wird im Kapitel Hilfsfunktionen erläutert.
int recv(int sockfd, void *buf, int len, unsigned int flags);
Dieser Aufruf gibt die Anzahl der in den Puffer gelesenen Bytes zurück, andernfalls wird bei einem Fehler -1 zurückgegeben.
Parameter
sockfd - Es ist ein Socket-Deskriptor, der von der Socket-Funktion zurückgegeben wird.
buf - Es ist der Puffer, in den die Informationen eingelesen werden.
len - Dies ist die maximale Länge des Puffers.
flags - Es wird auf 0 gesetzt.
Die sendto- Funktion
Die Sendto- Funktion wird verwendet, um Daten über UNCONNECTED-Datagramm-Sockets zu senden. Die Unterschrift lautet wie folgt:
int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen);
Dieser Aufruf gibt die Anzahl der gesendeten Bytes zurück, andernfalls wird bei einem Fehler -1 zurückgegeben.
Parameter
sockfd - Es ist ein Socket-Deskriptor, der von der Socket-Funktion zurückgegeben wird.
msg - Es ist ein Zeiger auf die Daten, die Sie senden möchten.
len - Dies ist die Länge der Daten, die Sie senden möchten (in Bytes).
flags - Es wird auf 0 gesetzt.
to - Es ist ein Zeiger auf struct sockaddr für den Host, an den Daten gesendet werden müssen.
tolen - Es wird auf sizeof (struct sockaddr) gesetzt.
Die Funktion recvfrom
Die Funktion recvfrom wird verwendet, um Daten von UNCONNECTED-Datagramm-Sockets zu empfangen.
int recvfrom(int sockfd, void *buf, int len, unsigned int flags struct sockaddr *from, int *fromlen);
Dieser Aufruf gibt die Anzahl der in den Puffer gelesenen Bytes zurück, andernfalls wird bei einem Fehler -1 zurückgegeben.
Parameter
sockfd - Es ist ein Socket-Deskriptor, der von der Socket-Funktion zurückgegeben wird.
buf - Es ist der Puffer, in den die Informationen eingelesen werden.
len - Dies ist die maximale Länge des Puffers.
flags - Es wird auf 0 gesetzt.
from - Es ist ein Zeiger auf struct sockaddr für den Host, auf dem Daten gelesen werden müssen.
fromlen - Es wird auf sizeof (struct sockaddr) gesetzt.
Die enge Funktion
Die Schließfunktion wird verwendet, um die Kommunikation zwischen dem Client und dem Server zu schließen. Die Syntax lautet wie folgt:
int close( int sockfd );
Dieser Aufruf gibt bei Erfolg 0 zurück, andernfalls gibt er bei Fehler -1 zurück.
Parameter
sockfd - Es ist ein Socket-Deskriptor, der von der Socket-Funktion zurückgegeben wird.
Die Shutdown - Funktion
Die Shutdown- Funktion wird verwendet, um die Kommunikation zwischen dem Client und dem Server ordnungsgemäß zu schließen. Diese Funktion bietet mehr Kontrolle im Vergleich zur Schließfunktion . Unten ist die Syntax des Herunterfahrens angegeben -
int shutdown(int sockfd, int how);
Dieser Aufruf gibt bei Erfolg 0 zurück, andernfalls gibt er bei Fehler -1 zurück.
Parameter
sockfd - Es ist ein Socket-Deskriptor, der von der Socket-Funktion zurückgegeben wird.
how - Geben Sie eine der Zahlen ein -
0 - zeigt an, dass das Empfangen nicht erlaubt ist,
1 - zeigt an, dass das Senden nicht erlaubt ist, und
2- zeigt an, dass sowohl Senden als auch Empfangen nicht zulässig sind. Wenn how auf 2 gesetzt ist, ist es dasselbe wie close ().
Die select - Funktion
Die Auswahlfunktion gibt an, welcher der angegebenen Dateideskriptoren zum Lesen oder Schreiben bereit ist oder eine Fehlerbedingung aussteht.
Wenn eine Anwendung recv oder recvfrom aufruft , wird sie blockiert, bis Daten für diesen Socket eintreffen. Eine Anwendung kann eine andere nützliche Verarbeitung ausführen, während der eingehende Datenstrom leer ist. Eine andere Situation ist, wenn eine Anwendung Daten von mehreren Sockets empfängt.
Das Aufrufen von recv oder recvfrom an einem Socket, dessen Eingabewarteschlange keine Daten enthält, verhindert den sofortigen Empfang von Daten von anderen Sockets. Der Funktionsaufruf select löst dieses Problem, indem das Programm alle Socket-Handles abfragen kann, um festzustellen, ob sie für nicht blockierende Lese- und Schreibvorgänge verfügbar sind.
Unten ist die Syntax von select - angegeben.
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout);
Dieser Aufruf gibt bei Erfolg 0 zurück, andernfalls gibt er bei Fehler -1 zurück.
Parameter
nfds- Gibt den Bereich der zu testenden Dateideskriptoren an. Die Funktion select () testet Dateideskriptoren im Bereich von 0 bis nfds-1
readfds- Es zeigt auf ein Objekt vom Typ fd_set , das bei der Eingabe die zu lesenden Dateideskriptoren angibt und bei der Ausgabe angibt, welche Dateideskriptoren zum Lesen bereit sind. Es kann NULL sein, um eine leere Menge anzuzeigen.
writefds- Es zeigt auf ein Objekt vom Typ fd_set , das bei der Eingabe die zu beschreibenden Dateideskriptoren angibt und bei der Ausgabe angibt, welche Dateideskriptoren schreibbereit sind. Es kann NULL sein, um eine leere Menge anzuzeigen.
exceptfds- Es zeigt auf ein Objekt vom Typ fd_set , das bei der Eingabe die Dateideskriptoren angibt, die auf anstehende Fehlerbedingungen überprüft werden sollen, und bei der Ausgabe angibt, bei welchen Dateideskriptoren Fehlerbedingungen anstehen. Es kann NULL sein, um eine leere Menge anzuzeigen.
timeout- Es zeigt auf eine Zeitstruktur, die angibt, wie lange der Auswahlaufruf die Deskriptoren für eine verfügbare E / A-Operation abfragen soll. Wenn der Timeout-Wert 0 ist, wird select sofort zurückgegeben. Wenn das Timeout-Argument NULL ist, wird select blockiert, bis mindestens ein Datei- / Socket-Handle für eine verfügbare E / A-Operation bereit ist. Andernfalls wird select nach Ablauf der Zeitspanne im Timeout zurückgegeben ODER, wenn mindestens ein Datei- / Socket-Deskriptor für eine E / A-Operation bereit ist.
Der Rückgabewert von select ist die Anzahl der Handles, die in den Dateideskriptorsätzen angegeben sind, die für die E / A bereit sind. Wenn das im Timeout-Feld angegebene Zeitlimit erreicht ist, wählen Sie return 0 aus. Die folgenden Makros zum Bearbeiten eines Dateideskriptorsatzes sind vorhanden:
FD_CLR(fd, &fdset)- Löscht das Bit für den Dateideskriptor fd im Dateideskriptorsatz fdset.
FD_ISSET(fd, &fdset)- Gibt einen Wert ungleich Null zurück, wenn das Bit für den Dateideskriptor fd in dem Dateideskriptorsatz gesetzt ist, auf den fdset zeigt , andernfalls 0.
FD_SET(fd, &fdset) - Setzt das Bit für den Dateideskriptor fd im Dateideskriptorsatz fdset.
FD_ZERO(&fdset) - Initialisiert den Dateideskriptorsatz fdset so, dass er für alle Dateideskriptoren null Bit enthält.
Das Verhalten dieser Makros ist undefiniert, wenn das Argument fd kleiner als 0 oder größer oder gleich FD_SETSIZE ist.
Beispiel
fd_set fds;
struct timeval tv;
/* do socket initialization etc.
tv.tv_sec = 1;
tv.tv_usec = 500000;
/* tv now represents 1.5 seconds */
FD_ZERO(&fds);
/* adds sock to the file descriptor set */
FD_SET(sock, &fds);
/* wait 1.5 seconds for any data to be read from any single socket */
select(sock+1, &fds, NULL, NULL, &tv);
if (FD_ISSET(sock, &fds)) {
recvfrom(s, buffer, buffer_len, 0, &sa, &sa_len);
/* do something */
}
else {
/* do something else */
}