гнездо подключения() против привязки()


и connect() и bind() системные вызовы 'связывают' дескриптор файла сокета с адресом (обычно комбинацией ip/порта). Их прототипы похожи: -

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

и

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

какова точная разница между 2 вызовами? Когда следует использовать connect() и когда bind()?

в частности, в некоторых образцах клиентских кодов сервера обнаружено, что клиент использует connect() и сервер, используя bind() звонок. Причина была не до конца ясна мне.

6 81

6 ответов:

чтобы сделать понимание лучше, давайте узнаем, где именно bind и connect входит в картину,

далее к позиционированию двух вызовов, как уточнил Сурав,

bind () связывает сокет с его локальным адресом [вот почему серверная сторона связывает, так что клиенты могут использовать этот адрес для подключения к серверу.] connect () используется для подключения к удаленному адресу [server], поэтому является клиентской стороной, connect [read as: connect to server] is используемый.

мы не можем использовать их взаимозаменяемо (даже если у нас есть клиент/сервер на одной машине) из-за определенных ролей и соответствующей реализации.

далее я буду рекомендовать соотносить эти вызовы TCP / IP handshake .

enter image description here

Итак, кто отправит SYN сюда, это будет connect() . Хотя bind() используется для определения конечной точки связи.

надеюсь, что это помогает!!

один лайнер :bind() в адрес, connect() на удаленный адрес.

цитата из man-страницы bind()

bind () назначает адрес, указанный addr, сокету, на который ссылается файловый дескриптор sockfd. addrlen определяет размер, в байтах, адресной структуры, на которую указывает addr. Традиционно эта операция называется "присвоение имени сокету".

и, с то же самое для connect()

системный вызов connect () соединяет сокет, на который ссылается файловый дескриптор sockfd, с адресом, указанным addr.

разъяснить

  • bind() связывает сокет с локальным адресом [вот почему на стороне сервера binds, так что клиенты могут использовать этот адрес для подключения на сервер.]
  • connect() используется для подключения к удаленному [сервер] адрес зачем быть на стороне клиента используется connect [читать как: подключение к серверу].

персонализация говорит запущенного процесса, чтобы претендовать на порт. то есть, он должен привязать себя к порту 80 и прослушивать входящие запросы. с помощью bind, ваш процесс становится сервером. когда вы используете подключения, вы скажите свой процесс, чтобы подключиться к порту, который уже используется. ваш процесс становится клиентом. разница важна: bind хочет порт, который не используется (чтобы он мог претендовать на него и стать сервером), а connect хочет порт, который уже используется (чтобы он мог подключиться к нему и поговорить с сервером). сервер)

из Википедии http://en.wikipedia.org/wiki/Berkeley_sockets#bind.28.29

connect ():

системный вызов connect () соединяет сокет, идентифицированный его файловым дескриптором, с удаленным хостом, указанным адресом этого хоста в списке аргументов.

некоторые типы сокетов являются бесконтактными, чаще всего сокеты протокола пользовательских дейтаграмм. Для этих сокетов connect приобретает особое значение: цель по умолчанию для отправка и получение данных устанавливается на заданный адрес, что позволяет использовать такие функции, как send() и recv() на разъемах без подключения.

connect () возвращает целое число, представляющее код ошибки: 0 представляет успех, а -1 представляет ошибку.

bind ():

bind () присваивает сокету адрес. Когда сокет создается с помощью socket (), ему присваивается только семейство протоколов, но не назначается адрес. Эта ассоциация с адрес должен быть выполнен с системным вызовом bind (), прежде чем сокет сможет принимать соединения с другими хостами. bind () принимает три аргумента:

sockfd, дескриптор, представляющий сокет для выполнения привязки. my_addr, указатель на структуру sockaddr, представляющую адрес для привязки. addrlen, поле socklen_t, задающее размер структуры sockaddr. Bind () возвращает 0 при успешном выполнении и -1 при возникновении ошибки.

примеры: 1.)С помощью Подключение

#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, '', 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.) Пример Привязки:

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

Я надеюсь, что это проясняет разницу

обратите внимание, что тип сокета, который вы заявляете, будет зависеть от того, что вам требуется, это крайне важно

я думаю, это поможет вашему пониманию, если вы думаете о connect() и listen() как коллег, а не connect() и bind(). Причина этого в том, что вы можете позвонить или пропустить bind() прежде чем кто-либо, хотя это редко хорошая идея, чтобы назвать его перед connect(), или не называть его перед listen().

если это помогает думать в терминах серверов и клиентов, это listen() что является отличительной чертой первого, и connect() последнего. bind() может быть найден или не найден - на любом.

если мы предположим, что наш сервер и клиент находятся на разных компьютерах, становится легче понять различные функции.

bind() действует локально, то есть он связывает конец соединения на машине, на которой он вызывается, с запрошенным адресом и назначает вам запрошенный порт. Он делает это независимо от того, будет ли эта машина клиентом или сервером. connect() инициирует подключение к серверу, то он подключается на запрошенный адрес и порт на сервере, от клиента. Этот сервер почти наверняка позвонил bind() до listen(), для того, чтобы вы могли знать, по какому адресу и Порту подключиться к нему с помощью connect().

если ты не позвонишь bind(), порт и адрес будут неявно назначены и привязаны к локальной машине для вас, когда вы вызываете либо connect() (клиент) или listen() (сервер). Однако это побочный эффект обоих, а не их цель. Порт назначенный таким образом является эфемерным.

важным моментом здесь является то, что клиент не должен быть привязан, потому что клиенты подключаются к серверам, и поэтому сервер будет знать адрес и порт клиента, даже если вы используете эфемерный порт, а не привязку к чему-то конкретному. С другой стороны, хотя сервер может вызвать listen() без вызова bind(), в этом случае им нужно будет обнаружить назначенный им эфемерный порт и сообщить об этом для любого клиента, который он хочет подключиться к нему.

я предполагаю, как вы упоминаете connect() вы заинтересованы в TCP, но это также переносится на UDP, где не вызывает bind() до первого sendto() (UDP-без подключения) также вызывает неявное назначение и привязку порта и адреса. Одна функция, которую вы не можете вызвать без привязки-это recvfrom(), который вернет ошибку, потому что без назначенного порта и связанного адреса нет ничего, чтобы получить от (или слишком много, в зависимости от того, как вы интерпретируете отсутствие привязки).

слишком долго; не читайте: разница заключается в том, устанавливается ли исходный (локальный) или целевой адрес/порт. Короче говоря,bind() установить источник и connect() задать пункт назначения. Независимо от TCP или UDP.

bind()

bind() установите локальный (исходный) адрес сокета. Это адрес, по которому принимаются пакеты. Пакеты, отправленные сокетом, несут это как исходный адрес, поэтому другой хост будет знать, куда отправить его обратно пакетированный.

если receive не требуется, адрес источника сокета бесполезен. Протоколы, такие как TCP, требуют, чтобы прием был включен для правильной отправки, поскольку конечный хост отправляет подтверждение, когда один или несколько пакетов прибыли (т. е. подтверждение).

connect()

  • TCP имеет состояние "подключено". connect() запускает TCP-код, чтобы попытаться установить соединение с другой стороной.
  • UDP не имеет состояния" подключено". connect() только установить адрес по умолчанию, куда отправляются пакеты, когда адрес не указан. Когда connect() не используется, sendto() или sendmsg() должен использоваться содержащий адрес назначения.

, когда connect() или вызывается функция отправки, и никакой адрес не привязан, Linux автоматически привязывает сокет к случайному порту. Для технических деталей, взгляните на inet_autobind() в исходном коде ядра Linux.

сторону Примечания

  • listen() только TCP.
  • In равен af_inet Семья, источник сокета или адрес назначения (struct sockaddr_in) состоит из IP-адреса (см. IP-заголовков), и порт TCP или UDP (см. TCP и UDP заголовок).