socket connect () vs bind()

Zarówno connect() jak i bind() wywołania systemowe "kojarzą" deskryptor pliku gniazda z adresem (zazwyczaj kombinacja ip/port). Ich prototypy są jak: -

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

I

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

Jaka jest dokładna różnica między 2 wywołaniami? Kiedy należy stosować connect() i kiedy bind()?

W szczególności, w niektórych przykładowych kodach klienta serwera, okazało się, że klient używa connect(), a serwer używa wywołania bind(). Powód nie był dla mnie do końca jasny.

Author: Sourav Ghosh, 2014-11-19

6 answers

Aby lepiej zrozumieć, dowiedzmy się, gdzie dokładnie bind i connect pojawia się w obrazie,

Dalej do pozycjonowania dwóch wywołań, jak wyjaśnia Sourav,

Bind kojarzy gniazdo z jego adresem lokalnym [dlatego po stronie serwera wiąże się, aby klienci mogli używać tego adresu do łączenia się z serwerem.] connect() służy do połączenia się ze zdalnym adresem [serwera], dlatego po stronie klienta jest używane connect [Czytaj jako: connect to server].

We nie możemy używać ich zamiennie (nawet jeśli mamy klienta / serwera na tej samej maszynie) z powodu określonych ról i odpowiedniej implementacji.

Dalej zalecam skorelowanie tych połączeń TCP / IP handshake .

Tutaj wpisz opis obrazka

Więc , kto wyśle tu SYN, będzie to connect (). Podczas gdy bind() służy do definiowania punktu końcowego komunikacji.

Mam nadzieję, że to pomoże!!

 155
Author: Jain Rach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-19 13:10:38

The one liner : bind() do własnego adresu, connect() do zdalnego adresu.

Cytowanie ze strony manbind()

Bind() przypisuje adres podany przez addr do gniazda, do którego odnosi się deskryptor pliku sockfd. addrlen określa rozmiar, w bajtach, struktury adresowej wskazywanej przez addr. Tradycyjnie operacja ta nazywana jest "przypisaniem nazwy do gniazda".

I, z tego samego dla connect()

Wywołanie systemowe connect () łączy Gniazdo określone przez deskryptor pliku sockfd z adresem określonym przez addr.

Aby wyjaśnić,

  • bind() kojarzy gniazdo z jego lokalnym adresem [dlatego po stronie serwera bind s, dzięki czemu klienci mogą używać tego adresu do łączenia na serwer.]
  • connect() jest używany do łączenia się z odległym [serwerem] adresem, to dlaczego po stronie klienta jest używane connect [Czytaj jako: connect to server].
 28
Author: Sourav Ghosh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-19 11:57:21

Bind mówi uruchomionemu procesowi, aby zażądał portu. tzn. powinien się związać z portem 80 i nasłuchiwać żądań incomming. dzięki bind twój proces staje się serwerem. gdy używasz connect, mówisz procesowi, aby połączył się z portem, który jest już w użyciu. twój proces staje się klientem. różnica jest ważna: bind chce portu, który nie jest używany (aby mógł go odebrać i stać się serwerem), a connect chce portu, który jest już używany (aby mógł się z nim połączyć i rozmawiać z Serwer)

 5
Author: Philipp Murry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-19 13:28:29

Z Wikipedii http://en.wikipedia.org/wiki/Berkeley_sockets#bind.28.29

Połącz():

Wywołanie systemowe connect () łączy Gniazdo, identyfikowane przez jego deskryptor pliku, ze zdalnym hostem określonym przez adres tego hosta na liście argumentów.

Niektóre typy gniazd są bezpołączeniowymi, najczęściej gniazda protokołu datagramowego użytkownika. Dla tych gniazd connect nabiera specjalnego znaczenia: domyślny cel wysyłania i odbierania danych otrzymuje ustawia pod podany adres, pozwalając na korzystanie z funkcji takich jak send () i recv () na gniazdach bezpołączeniowych.

Connect () Zwraca liczbę całkowitą reprezentującą kod błędu: 0 oznacza sukces, podczas gdy -1 oznacza błąd.

Bind():

Bind() przypisuje gniazdo do adresu. Gdy gniazdo jest tworzone za pomocą socket (), otrzymuje się tylko rodzinę protokołów, ale nie przypisano mu adresu. To skojarzenie z adresem musi być wykonane za pomocą wywołania systemowego bind () zanim gniazdo może przyjmować połączenia z innymi hostami. bind() przyjmuje trzy argumenty:

Sockfd, deskryptor reprezentujący gniazdo do wykonania wiązania. my_addr, wskaźnik do struktury sockaddr reprezentującej adres do powiązania. addrlen, pole socklen_t określające rozmiar struktury sockaddr. Bind () zwraca 0 po pomyślnym zakończeniu I -1 W przypadku wystąpienia błędu.

Przykłady: 1.) Za Pomocą 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.) Bind Przykład:

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);
    }

Mam nadzieję, że to wyjaśni różnica

Należy pamiętać, że typ gniazda, które deklarujesz, zależy od tego, czego potrzebujesz, jest to niezwykle ważne

 5
Author: Khan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-23 02:56:32

Myślę, że byłoby to pomocne w zrozumieniu, jeśli myślisz o connect() i listen() jako odpowiednikach, a nie connect() i bind(). Powodem tego jest to, że możesz wywołać lub pominąć bind() przed, chociaż rzadko jest dobrym pomysłem, aby zadzwonić przed connect(), lub nie zadzwonić przed listen().

Jeśli pomaga myśleć w kategoriach serwerów i klientów, to listen() jest znakiem rozpoznawczym pierwszego, a connect() drugiego. bind() można znaleźć - lub nie znaleźć-na jednym z nich.

Jeśli założymy nasz serwer i klient są na różnych maszynach, łatwiej jest zrozumieć różne funkcje.

bind() działa lokalnie, czyli wiąże koniec połączenia na maszynie, na której jest wywoływany, na żądany adres i przypisuje żądany port do ciebie. Robi to niezależnie od tego, czy ta maszyna będzie klientem, czy serwerem. connect() inicjuje połączenie z serwerem, czyli łączy się z żądanym adresem i portem na serwerze, z klient. Ten serwer prawie na pewno wywołał bind() przed listen(), abyś mógł wiedzieć, na którym adresie i porcie połączyć się z nim za pomocą connect().

Jeśli nie wywołasz bind(), port i adres zostaną domyślnie przypisane i powiązane na komputerze lokalnym dla ciebie, gdy wywołasz connect() (klient) lub listen() (serwer). Jest to jednak efekt uboczny obu, a nie ich cel. Port przypisany w ten sposób jest efemeryczny.

Ważnym punktem jest tutaj że Klient nie musi być związany, ponieważ klienci łączą się z serwerami, a więc serwer będzie znał adres i port klienta, nawet jeśli używasz efemerycznego portu, zamiast wiązania się z czymś konkretnym. Z drugiej strony, chociaż serwer mógłby wywołać listen() bez wywoływania bind(), w tym scenariuszu musiałby odkryć przypisany sobie Port efemeryczny i przekazać go każdemu klientowi, który chce się z nim połączyć.

Zakładam, że jak wspomnisz connect() jesteś zainteresowany TCP, ale to również przenosi się do UDP, gdzie nie wywołanie bind() przed pierwszym sendto() (UDP jest bez połączenia) również powoduje, że port i adres są domyślnie przypisane i powiązane. Jedną z funkcji, której nie można wywołać bez powiązania, jest recvfrom(), która zwróci błąd, ponieważ bez przypisanego portu i powiązanego adresu ,nie ma od czego odbierać (lub zbyt wiele, w zależności od tego, jak interpretujesz brak powiązania).

 1
Author: pjcard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-17 15:48:31

Too Long; Don ' t Read: różnica polega na tym, czy adres źródłowy (lokalny) lub adres docelowy/port jest ustawiany. W skrócie, bind() ustawić źródło i connect() ustawić cel. Niezależnie od TCP lub UDP.

bind()

bind() ustawia lokalny (źródłowy) adres gniazda. Jest to adres, na który odbierane są pakiety. Pakiety wysyłane przez gniazdo zawierają ten adres jako adres źródłowy, więc drugi host będzie wiedział, gdzie wysłać swoje pakiety.

Jeśli odbiór nie jest potrzebny adres źródłowy gniazda jest bezużyteczny. Protokoły takie jak TCP wymagają włączonego odbierania w celu poprawnego wysyłania, ponieważ host docelowy odsyła potwierdzenie, gdy jeden lub więcej pakietów dotarło(tj. potwierdzenie).

connect()

  • TCP ma stan "connected". connect() uruchamia kod TCP, aby spróbować nawiązać połączenie z drugą stroną.
  • UDP nie ma stanu "connected". connect() ustawia tylko domyślny adres, do którego pakiety są wysyłane, gdy nie podano adresu. Jeśli connect() nie jest używane, należy użyć sendto() lub sendmsg() zawierającego adres docelowy.

Kiedy {[1] } lub funkcja send jest wywoływana, a żaden adres nie jest związany, Linux automatycznie wiąże gniazdo do losowego portu. Szczegóły techniczne:inet_autobind() w kodzie źródłowym jądra Linuksa.

Side notes

  • listen() jest tylko TCP.
  • w rodzinie AF_INET , adres źródłowy lub docelowy gniazda (struct sockaddr_in) składa się z adresu IP adres (zobacz nagłówek IP) oraz port TCP lub UDP (zobacz TCP i UDP nagłówek).
 0
Author: Ricardo Biehl Pasquali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-02 20:56:24