Socket connect () vs bind ()


121

Sowohl connect()als auch bind()Systemaufrufe verknüpfen den Socket-Dateideskriptor mit einer Adresse (normalerweise eine IP / Port-Kombination). Ihre Prototypen sind wie: -

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

und

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

Was ist der genaue Unterschied zwischen 2 Anrufen? Wann sollte man connect()wann verwenden bind()?

Insbesondere wurde in einigen Beispielserver-Clientcodes festgestellt, dass der Client verwendet wird connect()und der Server den bind()Aufruf verwendet. Die Vernunft war mir nicht ganz klar.


19
In einem Satz: Binden ist an lokale Adresse, Verbinden ist an entfernte Adresse.
SHR

Antworten:


230

Um das Verständnis zu verbessern, wollen wir herausfinden, wo genau das Binden und Verbinden ins Bild kommt.

Nach der Positionierung von zwei Anrufen, wie von Sourav klargestellt,

bind () ordnet den Socket seiner lokalen Adresse zu [aus diesem Grund wird die Serverseite gebunden, sodass Clients diese Adresse verwenden können, um eine Verbindung zum Server herzustellen.] connect () wird verwendet, um eine Verbindung zu einer Remote-Adresse [Server] herzustellen , connect [gelesen als: Verbindung zum Server] wird verwendet.

Wir können sie aufgrund bestimmter Rollen und entsprechender Implementierung nicht austauschbar verwenden (selbst wenn sich Client / Server auf demselben Computer befinden).

Ich werde weiterhin empfehlen, diese Aufrufe TCP / IP-Handshake zu korrelieren.

Geben Sie hier die Bildbeschreibung ein

Also, wer wird SYN hier senden, es wird connect () sein. Während bind () zum Definieren des Kommunikationsendpunkts verwendet wird.

Hoffe das hilft!!


1
Dank bro. Mit dem Diagramm kann alles schnell ausstehen. Können Sie sagen, was der Unterschied hier ist, wenn wir udp verwenden?
Apm

8
accept () <br> sollte bis zur Verbindung vom Client unter den Block verschoben werden
tschodt

Ich denke, alle Knoten in einem Netzwerk in einem P2P-Netzwerk sollten Bind verwenden. Bin ich richtig?
Kapil

46

Der eine Liner: bind() zur eigenen Adresse, connect()zur entfernten Adresse.

Zitat aus der Manpage von bind()

bind () weist die durch addr angegebene Adresse dem Socket zu, auf den der Dateideskriptor sockfd verweist. addrlen gibt die Größe der Adressstruktur in Byte an, auf die addr verweist. Traditionell wird diese Operation als "Zuweisen eines Namens zu einem Socket" bezeichnet.

und aus dem gleichen für connect()

Der Systemaufruf connect () verbindet den Socket, auf den sich der Dateideskriptor sockfd bezieht, mit der von addr angegebenen Adresse.

Zu klären,

  • bind()ordnet den Socket seiner lokalen Adresse zu [aus diesem Grund serverseitig binds, damit Clients diese Adresse verwenden können, um eine Verbindung zum Server herzustellen.]
  • connect() wird verwendet, um eine Verbindung zu einer entfernten [Server] -Adresse herzustellen. Aus diesem Grund wird die clientseitige Verbindung [gelesen als: Verbindung zum Server] verwendet.

Können beispielsweise Server- und Clientprozesse austauschbar verwendet werden, wenn sie auf demselben Computer ausgeführt werden?
Siddhartha Ghosh

1
@SiddharthaGhosh Nein. Vielleicht befinden sich Client und Server auf demselben Computer, aber sie sind immer noch unterschiedliche Prozesse, oder? Beide APIs dienen ihrer eigenen Puprpose. Sie sind nieinterchangeable
Sourav Ghosh

Was genau ist in diesem Zusammenhang mit lokal und fern gemeint?
Siddhartha Ghosh

@SiddharthaGhosh local-> der Prozess selbst, remote-> der andere Prozess.
Sourav Ghosh

@SouravGhosh bedeutet dies, dass ich auf der Clientseite keinen Port angeben kann, an den gebunden werden soll?
Hengqi Chen

12

bind weist den laufenden Prozess an, einen Port zu beanspruchen. Das heißt, es sollte sich an Port 80 binden und auf eingehende Anforderungen warten. Mit bind wird Ihr Prozess zum Server. Wenn Sie connect verwenden, weisen Sie Ihren Prozess an, eine Verbindung zu einem bereits verwendeten Port herzustellen. Ihr Prozess wird zum Kunden. Der Unterschied ist wichtig: bind möchte einen Port, der nicht verwendet wird (damit er ihn beanspruchen und Server werden kann), und connect möchte einen Port, der bereits verwendet wird (damit er eine Verbindung herstellen und mit dem Server kommunizieren kann).


9

Aus Wikipedia http://en.wikipedia.org/wiki/Berkeley_sockets#bind.28.29

verbinden():

Der Systemaufruf connect () verbindet einen durch seinen Dateideskriptor identifizierten Socket mit einem Remote-Host, der durch die Adresse dieses Hosts in der Argumentliste angegeben wird.

Bestimmte Arten von Sockets sind verbindungslose, am häufigsten Benutzer-Datagramm-Protokoll-Sockets. Für diese Sockets hat connect eine besondere Bedeutung: Das Standardziel für das Senden und Empfangen von Daten wird auf die angegebene Adresse festgelegt, sodass Funktionen wie send () und recv () für verbindungslose Sockets verwendet werden können.

connect () gibt eine Ganzzahl zurück, die den Fehlercode darstellt: 0 steht für Erfolg, während -1 für einen Fehler steht.

binden():

bind () weist einer Adresse einen Socket zu. Wenn ein Socket mit socket () erstellt wird, erhält er nur eine Protokollfamilie, aber keine Adresse. Diese Zuordnung zu einer Adresse muss mit dem Systemaufruf bind () durchgeführt werden, bevor der Socket Verbindungen zu anderen Hosts akzeptieren kann. bind () akzeptiert drei Argumente:

sockfd, ein Deskriptor, der den Socket darstellt, für den die Bindung ausgeführt werden soll. my_addr, ein Zeiger auf eine sockaddr-Struktur, die die Adresse darstellt, an die gebunden werden soll. addrlen, ein socklen_t-Feld, das die Größe der sockaddr-Struktur angibt. Bind () gibt bei Erfolg 0 und -1 zurück, wenn ein Fehler auftritt.

Beispiele: 1.) Verwenden von Connect

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

int main(){
  int clientSocket;
  char buffer[1024];
  struct sockaddr_in serverAddr;
  socklen_t addr_size;

  /*---- Create the socket. The three arguments are: ----*/
  /* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */
  clientSocket = socket(PF_INET, SOCK_STREAM, 0);

  /*---- Configure settings of the server address struct ----*/
  /* Address family = Internet */
  serverAddr.sin_family = AF_INET;
  /* Set port number, using htons function to use proper byte order */
  serverAddr.sin_port = htons(7891);
  /* Set the IP address to desired host to connect to */
  serverAddr.sin_addr.s_addr = inet_addr("192.168.1.17");
  /* Set all bits of the padding field to 0 */
  memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);  

  /*---- Connect the socket to the server using the address struct ----*/
  addr_size = sizeof serverAddr;
  connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);

  /*---- Read the message from the server into the buffer ----*/
  recv(clientSocket, buffer, 1024, 0);

  /*---- Print the received message ----*/
  printf("Data received: %s",buffer);   

  return 0;
}

2.) Bindungsbeispiel:

int main()
{
    struct sockaddr_in source, destination = {};  //two sockets declared as previously
    int sock = 0;
    int datalen = 0;
    int pkt = 0;

    uint8_t *send_buffer, *recv_buffer;

    struct sockaddr_storage fromAddr;   // same as the previous entity struct sockaddr_storage serverStorage;
    unsigned int addrlen;  //in the previous example socklen_t addr_size;
    struct timeval tv;
    tv.tv_sec = 3;  /* 3 Seconds Time-out */
    tv.tv_usec = 0;

    /* creating the socket */         
    if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) 
        printf("Failed to create socket\n");

    /*set the socket options*/
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));

    /*Inititalize source to zero*/
    memset(&source, 0, sizeof(source));       //source is an instance of sockaddr_in. Initialization to zero
    /*Inititalize destinaton to zero*/
    memset(&destination, 0, sizeof(destination));


    /*---- Configure settings of the source address struct, WHERE THE PACKET IS COMING FROM ----*/
    /* Address family = Internet */
    source.sin_family = AF_INET;    
    /* Set IP address to localhost */   
    source.sin_addr.s_addr = INADDR_ANY;  //INADDR_ANY = 0.0.0.0
    /* Set port number, using htons function to use proper byte order */
    source.sin_port = htons(7005); 
    /* Set all bits of the padding field to 0 */
    memset(source.sin_zero, '\0', sizeof source.sin_zero); //optional


    /*bind socket to the source WHERE THE PACKET IS COMING FROM*/
    if (bind(sock, (struct sockaddr *) &source, sizeof(source)) < 0) 
        printf("Failed to bind socket");

    /* setting the destination, i.e our OWN IP ADDRESS AND PORT */
    destination.sin_family = AF_INET;                 
    destination.sin_addr.s_addr = inet_addr("127.0.0.1");  
    destination.sin_port = htons(7005); 

    //Creating a Buffer;
    send_buffer=(uint8_t *) malloc(350);
    recv_buffer=(uint8_t *) malloc(250);

    addrlen=sizeof(fromAddr);

    memset((void *) recv_buffer, 0, 250);
    memset((void *) send_buffer, 0, 350);

    sendto(sock, send_buffer, 20, 0,(struct sockaddr *) &destination, sizeof(destination));

    pkt=recvfrom(sock, recv_buffer, 98,0,(struct sockaddr *)&destination, &addrlen);
    if(pkt > 0)
        printf("%u bytes received\n", pkt);
    }

Ich hoffe das klärt den Unterschied

Bitte beachten Sie, dass der von Ihnen deklarierte Socket-Typ von Ihren Anforderungen abhängt. Dies ist äußerst wichtig


9

Ich denke, es würde Ihrem Verständnis helfen, wenn Sie an connect()und listen()als Gegenstücke denken connect()und nicht an bind(). Der Grund dafür ist, dass Sie bind()vorher anrufen oder weglassen können, obwohl es selten eine gute Idee ist, es vorher anzurufen oder vorher connect()nicht anzurufen listen().

Wenn es hilft, in Servern und Clients zu denken, ist listen()es das Markenzeichen des ersteren und connect()des letzteren. bind()kann auf gefunden werden - oder nicht gefunden werden.

Wenn wir davon ausgehen, dass sich Server und Client auf unterschiedlichen Computern befinden, wird es einfacher, die verschiedenen Funktionen zu verstehen.

bind()Handelt lokal, dh es bindet das Ende der Verbindung auf dem Computer, auf dem es aufgerufen wird, an die angeforderte Adresse und weist Ihnen den angeforderten Port zu. Dies geschieht unabhängig davon, ob es sich bei diesem Computer um einen Client oder einen Server handelt. connect()initiiert von einem Client aus eine Verbindung zu einem Server, dh eine Verbindung zu der angeforderten Adresse und dem angeforderten Port auf dem Server. Dieser Server wird fast sicher genannt bind()vor listen(), um für Sie in der Lage sein zu wissen , auf welcher Adresse und Port , um es zu verbinden mit der Verwendung connect().

Wenn Sie nicht anrufen bind(), werden Ihnen auf dem lokalen Computer implizit ein Port und eine Adresse zugewiesen und gebunden, wenn Sie entweder connect()(Client) oder listen()(Server) anrufen . Dies ist jedoch ein Nebeneffekt von beiden, nicht ihr Zweck. Ein auf diese Weise zugewiesener Port ist kurzlebig.

Ein wichtiger Punkt hierbei ist, dass der Client nicht gebunden werden muss, da Clients eine Verbindung zu Servern herstellen und der Server daher die Adresse und den Port des Clients kennt, obwohl Sie einen kurzlebigen Port verwenden, anstatt an etwas Bestimmtes zu binden. Auf der anderen Seite müsste der Server, obwohl er listen()ohne Anruf anrufen könnte bind(), in diesem Szenario den ihm zugewiesenen kurzlebigen Port ermitteln und dies jedem Client mitteilen, mit dem er eine Verbindung herstellen möchte.

Ich gehe davon aus, wie Sie erwähnen connect()Sie interessieren sich für TCP, aber dies trägt ebenfalls UDP über, wo nicht Aufruf bind()vor dem ersten sendto()(UDP ist verbindungslose) auch einen Port und Adresse bewirkt implizit zugewiesen und gebunden zu sein. Eine Funktion, die Sie ohne Bindung nicht aufrufen können, ist die recvfrom(), die einen Fehler zurückgibt, da ohne zugewiesenen Port und gebundene Adresse nichts zu empfangen ist (oder zu viel, je nachdem, wie Sie das Fehlen einer Bindung interpretieren).


1

Zu lang; Nicht lesen: Der Unterschied besteht darin, ob die Quelladresse (lokal) oder die Zieladresse / der Port festgelegt wird. Kurz gesagt, bind()stellen Sie die Quelle und connect()das Ziel ein. Unabhängig von TCP oder UDP.

bind()

bind()Stellen Sie die lokale (Quell-) Adresse des Sockets ein. Dies ist die Adresse, an der Pakete empfangen werden. Vom Socket gesendete Pakete tragen diese als Quelladresse, sodass der andere Host weiß, wohin er seine Pakete zurücksenden muss.

Wenn kein Empfang benötigt wird, ist die Socket-Quelladresse unbrauchbar. Protokolle wie TCP erfordern einen aktivierten Empfang, um ordnungsgemäß senden zu können, da der Zielhost eine Bestätigung zurücksendet, wenn ein oder mehrere Pakete eingetroffen sind (dh eine Bestätigung).

connect()

  • TCP hat einen "verbundenen" Zustand. connect()Löst den TCP-Code aus, um zu versuchen, eine Verbindung zur anderen Seite herzustellen.
  • UDP hat keinen "verbundenen" Status. connect()Legen Sie nur dann eine Standardadresse fest, an die Pakete gesendet werden, wenn keine Adresse angegeben ist. Wann connect()wird nicht verwendet sendto()oder sendmsg()muss mit der Zieladresse verwendet werden.

Wenn connect()oder eine Sendefunktion aufgerufen wird und keine Adresse gebunden ist, bindet Linux den Socket automatisch an einen zufälligen Port. Technische Details finden Sie inet_autobind()im Linux-Kernel-Quellcode.

Randnotizen

  • listen() ist nur TCP.
  • In der AF_INET- Familie besteht die Quell- oder Zieladresse ( struct sockaddr_in) des Sockets aus einer IP-Adresse (siehe IP-Header ) und einem TCP- oder UDP-Port (siehe TCP- und UDP- Header).
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.