Подтвердить что ты не робот

Socket connect() vs bind()

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

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

и

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

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

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

4b9b3361

Ответ 1

Чтобы лучше понять, давайте выясним, где именно связываются и соединяются,

В дополнение к позиционированию двух вызовов, как пояснил Сурав,

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

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

Далее я порекомендую соотнести эти звонки TCP/IP с рукопожатием.

enter image description here

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

Надеюсь это поможет!!

Ответ 2

Один лайнер: bind() для собственного адреса, connect() для удаленного адреса.

Цитата из справочной страницы bind()

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

и, от того же для connect()

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

Чтобы уточнить,

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

Ответ 3

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

Ответ 4

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

подключения():

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

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

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

Bind():

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

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

Примеры: 1.) Использование 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.) Пример привязки:

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

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

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

Ответ 5

Я думаю, что это поможет вашему пониманию, если вы будете думать о 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(), которая будет возвращать ошибку, потому что без назначенного порта и связанного адреса нечего получать (или слишком много, в зависимости от того, как вы интерпретируете отсутствие привязки).

Ответ 6

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

bind()

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

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

connect()

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

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

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

  • listen() только для TCP.
  • В семействе AF_INET адрес источника или назначения сокета (struct sockaddr_in) состоит из IP-адреса (см. Заголовок IP) и порта TCP или UDP (см. Заголовок TCP и UDP).