Heim > php教程 > PHP开发 > Detaillierte Erklärung von Socket

Detaillierte Erklärung von Socket

高洛峰
Freigeben: 2016-12-13 10:17:38
Original
1213 Leute haben es durchsucht

Wir sind uns des Werts des Informationsaustauschs bewusst. Wie kommunizieren Prozesse im Netzwerk? Wenn wir beispielsweise jeden Tag den Browser öffnen, um im Internet zu surfen, wie kommuniziert der Browserprozess mit dem Webserver? Wenn Sie QQ zum Chatten verwenden, wie kommuniziert der QQ-Prozess mit dem Server oder dem QQ-Prozess, auf dem sich Ihre Freunde befinden? Sind all diese auf Steckdosen angewiesen? Was ist also eine Steckdose? Welche Arten von Steckdosen gibt es? Es gibt auch grundlegende Funktionen von Sockets, die in diesem Artikel vorgestellt werden sollen. Der Hauptinhalt dieses Artikels ist wie folgt:

1. Wie kommuniziert man zwischen Prozessen im Netzwerk?

2. Was ist Socket?

3. Grundfunktionen von socket()

3.2. bind()-Funktion

3.3. ) Funktion

3.4, Funktion „accept()“

3.5, Funktionen „read()“, „write()“ usw.

3.6, Funktion „close()“

4 , Ausführliche Erläuterung des Drei-Wege-Handshakes von TCP zum Herstellen einer Verbindung im Socket

5. Ausführliche Erläuterung des Vier-Wege-Handshakes von TCP zum Freigeben der Verbindung im Socket

Ein Beispiel (Übung). it)

7. Hinterlassen Sie eine Frage und jeder ist willkommen, zu antworten! ! !

1. Wie kommuniziert man zwischen Prozessen im Netzwerk?

Es gibt viele Möglichkeiten der lokalen Interprozesskommunikation (IPC), aber sie können in den folgenden 4 Kategorien zusammengefasst werden:

Nachrichtenübermittlung (Pipeline, FIFO, Nachrichtenwarteschlange)

Synchronisation (Mutexe, Bedingungsvariablen, Lese-/Schreibsperren, Datei- und Schreibdatensatzsperren, Semaphoren)

Gemeinsamer Speicher (anonym und benannt)

Remote-Prozeduraufrufe (Solaris Gate und Sun RPC)

Aber das ist nicht das Thema dieses Artikels! Was wir diskutieren werden, ist die Frage, wie zwischen Prozessen im Netzwerk kommuniziert werden soll. Das erste zu lösende Problem besteht darin, einen Prozess eindeutig zu identifizieren, sonst ist eine Kommunikation unmöglich! Durch die Prozess-PID kann ein Prozess lokal eindeutig identifiziert werden, im Netzwerk funktioniert dies jedoch nicht. Tatsächlich hat uns die TCP/IP-Protokollsuite dabei geholfen, dieses Problem zu lösen. Die „IP-Adresse“ der Netzwerkschicht kann den Host im Netzwerk eindeutig identifizieren, während das „Protokoll + Port“ der Transportschicht die Anwendung eindeutig identifizieren kann (Prozess) im Host. Auf diese Weise kann das Triplett (IP-Adresse, Protokoll, Port) zur Identifizierung des Netzwerkprozesses verwendet werden, und die Prozesskommunikation im Netzwerk kann diese Markierung verwenden, um mit anderen Prozessen zu interagieren.

Anwendungen, die das TCP/IP-Protokoll verwenden, verwenden normalerweise Anwendungsprogrammierschnittstellen: Sockets von UNIX BSD und TLI von UNIX System V (bereits veraltet), um die Kommunikation zwischen Netzwerkprozessen zu erreichen. Derzeit verwenden fast alle Anwendungen Sockets, und jetzt ist die Prozesskommunikation im Netzwerk allgegenwärtig. Deshalb sage ich: „Alles ist Socket“.

2. Was ist Socket?

Oben wissen wir bereits, dass Prozesse im Netzwerk über Sockets kommunizieren. Was ist also ein Socket? Sockets stammen aus Unix, und eine der Grundphilosophien von Unix/Linux ist, dass „alles eine Datei ist“ und im Modus „Öffnen -> Lesen und Schreiben, Schreiben/Lesen -> Schließen“ betrieben werden kann. Nach meinem Verständnis ist Socket eine spezielle Datei und einige Socket-Funktionen sind Operationen darauf (E/A lesen/schreiben, öffnen, schließen). Wir werden diese Funktionen später vorstellen.

Der Ursprung des Wortes Socket

Die erste Verwendung im Bereich Netzwerk wurde in dem am 12. Februar 1970 veröffentlichten Dokument IETF RFC33 gefunden, das von Stephen Carr, Steve Crocker und Vint Cerf verfasst wurde . Laut dem Computer History Museum schrieb Croker: „Elemente eines Namespace können als Socket-Schnittstellen bezeichnet werden. Eine Socket-Schnittstelle bildet ein Ende einer Verbindung, und eine Verbindung kann vollständig durch ein Paar von Socket-Schnittstellen spezifiziert werden.“ Das Computer History Museum hinzugefügt: „Dies ist etwa 12 Jahre früher als die Socket-Schnittstellendefinition von BSD Der Socket stellt funktionale Schnittstellen bereit, die diesen Vorgängen entsprechen. Im Folgenden wird TCP als Beispiel verwendet, um mehrere grundlegende Socket-Schnittstellenfunktionen vorzustellen.

3.1, socket()-Funktion

int socket(int domain, int type, int Protocol);

Die Socket-Funktion entspricht dem gewöhnlichen Öffnungsvorgang Dateien. Der normale Vorgang zum Öffnen einer Datei gibt einen Dateideskriptor zurück, und socket () wird zum Erstellen eines Socket-Deskriptors (Socket-Deskriptor) verwendet, der einen Socket eindeutig identifiziert. Dieser Socket-Deskriptor ist derselbe wie der Dateideskriptor. Er wird in nachfolgenden Vorgängen verwendet. Er wird als Parameter zum Ausführen einiger Lese- und Schreibvorgänge verwendet.

Genauso wie Sie verschiedene Parameterwerte an fopen übergeben können, um verschiedene Dateien zu öffnen. Beim Erstellen eines Sockets können Sie auch verschiedene Parameter angeben, um unterschiedliche Socket-Deskriptoren zu erstellen. Die drei Parameter der Socket-Funktion sind:

Domäne: die Protokolldomäne, auch Protokollfamilie genannt. Zu den häufig verwendeten Protokollfamilien gehören AF_INET, AF_INET6, AF_LOCAL (oder AF_UNIX, Unix-Domänen-Socket), AF_ROUTE usw. Die Protokollfamilie bestimmt den Adresstyp des Sockets und die entsprechende Adresse muss bei der Kommunikation verwendet werden. AF_INET bestimmt beispielsweise die Verwendung einer Kombination aus IPv4-Adresse (32-Bit) und Portnummer (16-Bit) und AF_UNIX bestimmt um einen absoluten Namen als Adresse zu verwenden.

Typ: Geben Sie den Socket-Typ an. Zu den häufig verwendeten Socket-Typen gehören SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_PACKET, SOCK_SEQPACKET usw. (Welche Socket-Typen gibt es?).

Protokoll: Daher der Name, der die Angabe des Protokolls bedeutet. Zu den häufig verwendeten Protokollen gehören IPPROTO_TCP, IPPTOTO_UDP, IPPROTO_SCTP, IPPROTO_TIPC usw., die jeweils dem TCP-Übertragungsprotokoll, dem UDP-Übertragungsprotokoll, dem STCP-Übertragungsprotokoll und dem TIPC-Übertragungsprotokoll entsprechen (ich werde dieses Protokoll separat besprechen!).

Hinweis: Der oben genannte Typ und das Protokoll können nicht beliebig kombiniert werden. Beispielsweise kann SOCK_STREAM nicht mit IPPROTO_UDP kombiniert werden. Wenn das Protokoll 0 ist, wird automatisch das dem Typ entsprechende Standardprotokoll ausgewählt.

Wenn wir Socket aufrufen, um einen Socket zu erstellen, ist der zurückgegebene Socket-Deskriptor im Raum der Protokollfamilie (Adressfamilie, AF_XXX) vorhanden, hat jedoch keine spezifische Adresse. Wenn Sie ihm eine Adresse zuweisen möchten, müssen Sie die Funktion bind() aufrufen, andernfalls weist das System beim Aufruf von connect() oder listen() automatisch einen Port zufällig zu.

3.2. bind()-Funktion

Wie oben erwähnt, weist die bind()-Funktion dem Socket eine bestimmte Adresse in einer Adressfamilie zu. Beispielsweise wird dem Socket entsprechend AF_INET und AF_INET6 eine Kombination aus IPv4- oder IPv6-Adresse und Portnummer zugewiesen.

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

Die drei Parameter der Funktion sind:

sockfd: das heißt, das Socket-Beschreibungswort, das durch die Funktion socket() erstellt wird und einen Socket eindeutig identifiziert. Die Funktion bind() bindet einen Namen an diesen Deskriptor.

addr: ein const struct sockaddr * Zeiger, der auf die Protokolladresse zeigt, die an sockfd gebunden werden soll. Diese Adressstruktur variiert je nach Adressprotokollfamilie, wenn die Adresse den Socket erstellt. Beispielsweise entspricht IPv4:

struct sockaddr_in {
    sa_family_t    sin_family; /* address family: AF_INET */
    in_port_t      sin_port;   /* port in network byte order */
    struct in_addr sin_addr;   /* internet address */};/* Internet address. */struct in_addr {
    uint32_t       s_addr;     /* address in network byte order */};
ipv6对应的是: 
struct sockaddr_in6 { 
    sa_family_t     sin6_family;   /* AF_INET6 */ 
    in_port_t       sin6_port;     /* port number */ 
    uint32_t        sin6_flowinfo; /* IPv6 flow information */ 
    struct in6_addr sin6_addr;     /* IPv6 address */ 
    uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */ };struct in6_addr { 
    unsigned char   s6_addr[16];   /* IPv6 address */ };
Unix域对应的是: 
#define UNIX_PATH_MAX    108struct sockaddr_un { 
    sa_family_t sun_family;               /* AF_UNIX */ 
    char        sun_path[UNIX_PATH_MAX];  /* pathname */ };
addrlen:对应的是地址的长度。
Nach dem Login kopieren

Normalerweise bindet der Server eine bekannte Adresse (z. B. IP-Adresse + Port). (Nummer) wird zur Bereitstellung von Diensten verwendet, und Kunden können sich über sie mit dem Server verbinden; der Client muss sie nicht angeben, und das System weist automatisch eine Kombination aus Portnummer und eigener IP-Adresse zu. Aus diesem Grund ruft der Server normalerweise bind() auf, bevor er lauscht, aber der Client ruft es nicht auf. Stattdessen generiert das System zufällig eines während connect().

Netzwerk-Byte-Reihenfolge und Host-Byte-Reihenfolge

Host-Byte-Reihenfolge ist das, was wir normalerweise Big-Endian- und Little-Endian-Modi nennen: Verschiedene CPUs haben unterschiedliche Byte-Reihenfolge-Typen, diese Wörter Abschnittsreihenfolge beziehen sich auf die Reihenfolge in dem ganze Zahlen im Speicher gespeichert werden. Dies wird als Host-Reihenfolge bezeichnet. Die Standarddefinitionen von Big-Endian und Little-Endian werden wie folgt zitiert:

a) Little-Endian bedeutet, dass die niederwertigen Bytes am unteren Adressende des Speichers und die höherwertigen Bytes angeordnet sind Bytes sind am oberen Adressende des Speichers angeordnet.

b) Big-Endian bedeutet, dass die höherwertigen Bytes am unteren Adressende des Speichers und die niederwertigen Bytes am oberen Adressende des Speichers angeordnet sind.

Netzwerk-Byte-Reihenfolge: 4-Byte-32-Bit-Werte werden in der folgenden Reihenfolge übertragen: zuerst 0 ~ 7 Bit, dann 8 ~ 15 Bit, dann 16 ~ 23 Bit und schließlich 24 ~ 31 Bit. Dieser Übertragungsauftrag wird Big-Endian genannt. Da alle binären Ganzzahlen im TCP/IP-Header bei der Übertragung über das Netzwerk in dieser Reihenfolge vorliegen müssen, wird sie auch als Netzwerk-Byte-Reihenfolge bezeichnet. Die Bytereihenfolge ist, wie der Name schon sagt, die Reihenfolge, in der Daten, die größer als ein Byte sind, im Speicher gespeichert werden. Bei Daten mit einem Byte gibt es kein Problem mit der Reihenfolge.

Also: Wenn Sie eine Adresse an einen Socket binden, konvertieren Sie bitte zuerst die Host-Byte-Reihenfolge in die Netzwerk-Byte-Reihenfolge und gehen Sie nicht davon aus, dass die Host-Byte-Reihenfolge „Big“ verwendet, was mit der Netzwerk-Byte-Reihenfolge identisch ist. -Endian. Es gab Morde, die durch dieses Problem verursacht wurden! Dieses Problem hat viele unerklärliche Probleme im Projektcode des Unternehmens verursacht. Denken Sie daher bitte daran, keine Annahmen über die Host-Byte-Reihenfolge zu treffen und diese unbedingt in die Netzwerk-Byte-Reihenfolge umzuwandeln, bevor Sie sie dem Socket zuweisen.

3.3, listen(), connect() Funktionen

Wenn Sie ein Server sind, rufen Sie nach dem Aufruf von socket() und bind() listen() auf, um den Socket abzuhören. Wenn der Client connect() aufruft, um eine Verbindungsanforderung auszugeben, empfängt der Server die Anforderung . .

int listen(int sockfd, int backlog);int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

Der erste Parameter der Listen-Funktion ist The Der zu überwachende Socket-Deskriptor ist die maximale Anzahl von Verbindungen, die für den entsprechenden Socket in die Warteschlange gestellt werden können. Der von der Funktion socket() erstellte Socket ist standardmäßig ein aktiver Typ, und die Listen-Funktion ändert den Socket in einen passiven Typ und wartet auf die Verbindungsanforderung des Clients.

Der erste Parameter der Verbindungsfunktion ist der Socket-Deskriptor des Clients, der zweite Parameter ist die Socket-Adresse des Servers und der dritte Parameter ist die Länge der Socket-Adresse. Der Client stellt eine Verbindung mit dem TCP-Server her, indem er die Verbindungsfunktion aufruft.

3.4. Funktion „accept()“

Nachdem der TCP-Server nacheinander socket(), bind() und listen() aufgerufen hat, lauscht er auf die angegebene Socket-Adresse. Nachdem er socket() und connect() nacheinander aufgerufen hat, sendet der TCP-Client eine Verbindungsanforderung an den TCP-Server. Nachdem der TCP-Server diese Anfrage abgehört hat, ruft er die Funktion „accept()“ auf, um die Anfrage zu empfangen, sodass die Verbindung hergestellt wird. Anschließend können Sie Netzwerk-E/A-Vorgänge starten, die gewöhnlichen E/A-Vorgängen zum Lesen und Schreiben von Dateien ähneln.

int take(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

Der erste Parameter der Accept-Funktion ist der Socket-Deskriptor des Servers und der zweite Parameter ist der Zeiger zu struct sockaddr *, wird verwendet, um die Protokolladresse des Clients zurückzugeben. Der dritte Parameter ist die Länge der Protokolladresse. Wenn accpet erfolgreich ist, ist der Rückgabewert ein neuer Deskriptor, der automatisch vom Kernel generiert wird und die TCP-Verbindung zum zurückkehrenden Client darstellt.

Hinweis: Der erste Parameter von Accept ist der Socket-Deskriptor des Servers, der generiert wird, wenn der Server mit dem Aufruf der Socket()-Funktion beginnt. Er wird als Listening-Socket-Deskriptor bezeichnet und die Accept-Funktion gibt die Beschreibung des verbundenen Sockets zurück . Charakter. Ein Server erstellt normalerweise nur einen Listening-Socket-Deskriptor, der während des Lebenszyklus des Servers vorhanden ist. Der Kernel erstellt einen verbundenen Socket-Deskriptor für jede vom Serverprozess akzeptierte Client-Verbindung. Wenn der Server die Bereitstellung eines Clients abgeschlossen hat, wird der entsprechende verbundene Socket-Deskriptor geschlossen.

3.5, read(), write() und andere Funktionen

Alles ist bereit und die Verbindung zwischen Server und Client wurde hergestellt. Netzwerk-E/A kann für Lese- und Schreibvorgänge aufgerufen werden, wodurch die Kommunikation zwischen verschiedenen Prozessen im Netzwerk realisiert wird! Netzwerk-E/A-Vorgänge haben die folgenden Gruppen:

read()/write()

recv()/send()

readv()/writev()

recvmsg()/sendmsg()

recvfrom()/sendto()

Ich empfehle die Verwendung der Funktion recvmsg()/sendmsg(), diese beiden Funktionen sind die meisten Dank der vielseitigen I/O-Funktionen können Sie die anderen oben genannten Funktionen tatsächlich durch diese beiden Funktionen ersetzen. Ihre Deklarationen lauten wie folgt:

#include

ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);

            #include
            #include

        ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

ssize_t sendto(int sockfd, const void *buf, size_t len , struct sockadd r *src_addr, socklen_t *addrlen);

ssize_t sendmsg (int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags );

Die Lesefunktion ist für das Lesen von fd-Inhalten verantwortlich. Wenn der Lesevorgang erfolgreich ist, gibt read die tatsächliche Anzahl der gelesenen Bytes zurück. Wenn der zurückgegebene Wert 0 ist, bedeutet dies, dass das Ende erreicht ist Wenn die Datei kleiner als 0 ist, bedeutet dies, dass ein Fehler aufgetreten ist. Wenn der Fehler EINTR lautet, bedeutet dies, dass der Lesevorgang durch einen Interrupt verursacht wurde. Wenn es sich um ECONNREST handelt, liegt ein Problem mit der Netzwerkverbindung vor.

Die Schreibfunktion schreibt den Inhalt von nbytes Bytes in buf in den Dateideskriptor fd. Gibt bei Erfolg die Anzahl der geschriebenen Bytes zurück. Bei einem Fehler wird -1 zurückgegeben und die Variable errno gesetzt. In Netzwerkprogrammen gibt es zwei Möglichkeiten, wenn wir in den Socket-Dateideskriptor schreiben. 1) Der Rückgabewert von write ist größer als 0, was darauf hinweist, dass ein Teil oder alle Daten geschrieben wurden. 2) Der zurückgegebene Wert ist kleiner als 0 und es ist ein Fehler aufgetreten. Wir müssen uns entsprechend der Fehlerart damit befassen. Wenn der Fehler EINTR ist, bedeutet dies, dass beim Schreiben ein Interrupt-Fehler aufgetreten ist. Wenn es EPIPE ist, bedeutet dies, dass ein Problem mit der Netzwerkverbindung vorliegt (die andere Partei hat die Verbindung geschlossen).

Ich werde diese Paare von E/A-Funktionen nicht einzeln vorstellen. Weitere Informationen finden Sie im Man-Dokument. In den folgenden Beispielen wird Baidu oder Google verwendet.

3.6, close()-Funktion

在服务器与客户端建立连接之后,会进行一些读写操作,完成了读写操作就要关闭相应的socket描述字,好比操作完打开的文件要调用fclose关闭打开的文件。

#include int close(int fd);

close一个TCP socket的缺省行为时把该socket标记为以关闭,然后立即返回到调用进程。该描述字不能再由调用进程使用,也就是说不能再作为read或write的第一个参数。

注意:close操作只是使相应socket描述字的引用计数-1,只有当引用计数为0的时候,才会触发TCP客户端向服务器发送终止连接请求。

4、socket中TCP的三次握手建立连接详解

我们知道tcp建立连接要进行“三次握手”,即交换三个分组。大致流程如下:

客户端向服务器发送一个SYN J

服务器向客户端响应一个SYN K,并对SYN J进行确认ACK J+1

客户端再想服务器发一个确认ACK K+1

只有就完了三次握手,但是这个三次握手发生在socket的那几个函数中呢?请看下图:

Detaillierte Erklärung von Socket

图1、Detaillierte Erklärung von Socket

从图中可以看出,当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。

总结:客户端的connect在三次握手的第二个次返回,而服务器端的accept在三次握手的第三次返回。

5、socket中TCP的四次握手释放连接详解

上面介绍了socket中TCP的三次握手建立过程,及其涉及的socket函数。现在我们介绍socket中的四次握手释放连接的过程,请看下图:

Detaillierte Erklärung von Socket

图2、Detaillierte Erklärung von Socket

图示过程如下:

某个应用进程首先调用close主动关闭连接,这时TCP发送一个FIN M;

另一端接收到FIN M之后,执行被动关闭,对这个FIN进行确认。它的接收也作为文件结束符传递给应用进程,因为FIN的接收意味着应用进程在相应的连接上再也接收不到额外数据;

一段时间之后,接收到文件结束符的应用进程调用close关闭它的socket。这导致它的TCP也发送一个FIN N;

接收到这个FIN的源发送端TCP对它进行确认。

这样每个方向上都有一个FIN和ACK。

6、一个例子(实践一下)

说了这么多了,动手实践一下。下面编写一个简单的服务器、客户端(使用TCP)——服务器端一直监听本机的6666号端口,如果收到连接请求,将接收请求并接收客户端发来的消息;客户端与服务器端建立连接并发送一条消息。

服务器端代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>

#define MAXLINE 4096

int main(int argc, char** argv)
{
    int    listenfd, connfd;
    struct sockaddr_in     servaddr;
    char    buff[4096];
    int     n;

    if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
    printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
    exit(0);
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(6666);

    if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
    printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
    exit(0);
    }

    if( listen(listenfd, 10) == -1){
    printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
    exit(0);
    }

    printf("======waiting for client&#39;s request======\n");
    while(1){
    if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1){
        printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
        continue;
    }
    n = recv(connfd, buff, MAXLINE, 0);
    buff[n] = &#39;\0&#39;;
    printf("recv msg from client: %s\n", buff);
    close(connfd);
    }

    close(listenfd);
}
Nach dem Login kopieren

当然上面的代码很简单,也有很多缺点,这就只是简单的演示socket的基本函数使用。其实不管有多复杂的网络程序,都使用的这些基本函数。上面的服务器使用的是迭代模式的,即只有处理完一个客户端请求才会去处理下一个客户端的请求,这样的服务器处理能力是很弱的,现实中的服务器都需要有并发处理能力!为了需要并发处理,服务器需要fork()一个新的进程或者线程去处理请求等。

7、动动手

留下一个问题,欢迎大家回帖回答!!!是否熟悉Linux下网络编程?如熟悉,编写如下程序完成如下功能:

服务器端:

接收地址192.168.100.2的客户端信息,如信息为“Client Query”,则打印“Receive Query”

客户端:

Senden Sie die Informationen „Client-Abfragetest“, „Cleint-Abfrage“, „Client-Abfrage beenden“ nacheinander an den Server unter der Adresse 192.168.100.168 und beenden Sie den Vorgang.

Die in der Frage angezeigte IP-Adresse kann entsprechend der tatsächlichen Situation ermittelt werden.


Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Empfehlungen
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage