web-dev-qa-db-fra.com

socket connect () vs bind ()

Les appels système connect() et bind() associent le descripteur de fichier de socket à une adresse (généralement une combinaison ip/port). Leurs prototypes sont comme: -

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

et

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

Quelle est la différence exacte entre 2 appels? Quand faut-il utiliser connect() et quand bind()?

Spécifiquement, dans certains exemples de codes client de serveur, il a été constaté que le client utilise connect() et que le serveur utilise l'appel bind(). La raison n'était pas tout à fait claire pour moi.

98
Siddhartha Ghosh

Pour améliorer la compréhension, voyons où se trouvent exactement ce qui se lie et se connecte,

Suite au positionnement de deux appels, comme précisé par Sourav,

bind () associe le socket à son adresse locale [c'est pourquoi les liaisons côté serveur permettent aux clients d'utiliser cette adresse pour se connecter au serveur.] connect () est utilisé pour se connecter à une adresse [serveur] distante, c'est pourquoi son côté client , connect [lu en tant que: connectez-vous au serveur] est utilisé.

Nous ne pouvons pas les utiliser de manière interchangeable (même si nous avons un client/serveur sur le même ordinateur) en raison de rôles spécifiques et de la mise en œuvre correspondante.

Je recommanderai en outre de mettre en corrélation ces appels TCP/IP.

enter image description here

Donc, qui enverra SYN ici, ce sera connect (). Alors que bind () est utilisé pour définir le noeud final de la communication.

J'espère que cela t'aides!!

186
Jain Rach

La ligne unique: bind() vers sa propre adresse, connect() vers son adresse distante.

Citant la page de manuel de bind()

bind () assigne l'adresse spécifiée par addr au socket référencé par le descripteur de fichier sockfd. addrlen spécifie la taille, en octets, de la structure d'adresse indiquée par addr. Traditionnellement, cette opération s'appelle "assigner un nom à un socket".

et, de la même chose pour connect()

L'appel système connect () connecte le socket référencé par le descripteur de fichier sockfd à l'adresse spécifiée par addr.

Clarifier,

  • bind() associe le socket à son adresse locale [c'est pourquoi côté serveur binds, afin que les clients puissent utiliser cette adresse pour se connecter au serveur.]
  • connect() est utilisé pour se connecter à une adresse [serveur] distante, c'est pourquoi son côté client est utilisé, connect [lire comme: connectez-vous au serveur] est utilisé.
38
Sourav Ghosh

bind indique au processus en cours de réclamer un port. c'est-à-dire qu'il doit se lier au port 80 et écouter les demandes entrantes. avec bind, votre processus devient un serveur. lorsque vous utilisez connect, vous indiquez à votre processus de se connecter à un port déjà utilisé. votre processus devient un client. la différence est importante: bind veut un port qui n'est pas utilisé (pour pouvoir le revendiquer et devenir un serveur), et connect veut un port déjà utilisé (pour pouvoir s'y connecter et dialoguer avec le serveur)

7
Philipp Murry

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

connect ():

L'appel système connect () connecte un socket, identifié par son descripteur de fichier, à un hôte distant spécifié par l'adresse de cet hôte dans la liste des arguments.

Certains types de sockets sont des connexions sans connexion, le plus souvent des sockets de protocole de datagramme utilisateur. Pour ces sockets, connect revêt une signification particulière: la cible par défaut pour l'envoi et la réception de données est définie sur l'adresse indiquée, ce qui permet d'utiliser des fonctions telles que send () et recv () sur des sockets sans connexion.

connect () renvoie un entier représentant le code d'erreur: 0 représente le succès, tandis que -1 représente une erreur.

bind ():

bind () assigne un socket à une adresse. Lorsqu'un socket est créé à l'aide de socket (), il se voit uniquement attribuer une famille de protocoles, mais aucune adresse n'est attribuée. Cette association avec une adresse doit être effectuée avec l'appel système bind () avant que le socket puisse accepter les connexions avec d'autres hôtes. bind () prend trois arguments:

sockfd, un descripteur représentant le socket sur lequel effectuer la liaison. my_addr, un pointeur sur une structure sockaddr représentant l'adresse à laquelle se lier. addrlen, un champ socklen_t spécifiant la taille de la structure sockaddr. Bind () renvoie 0 en cas de succès et -1 en cas d'erreur.

Exemples: 1.) Utilisation de 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.) Exemple de liaison:

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

J'espère que ça clarifie la différence

Veuillez noter que le type de socket que vous déclarez dépendra de ce dont vous avez besoin, ce qui est extrêmement important.

7
Khan

Je pense que cela aiderait votre compréhension si vous considérez connect() et listen() comme des contreparties, plutôt que connect() et bind(). La raison en est que vous pouvez appeler ou omettre bind() avant, bien que ce soit rarement une bonne idée de l’appeler avant connect(), ou de ne pas l’appeler avant listen().

S'il est utile de penser en termes de serveurs et de clients, c'est listen() qui est la marque du premier et connect() le second. bind() peut être trouvé - ou introuvable - sur l'un ou l'autre.

Si nous supposons que notre serveur et notre client sont sur des machines différentes, il devient plus facile de comprendre les différentes fonctions.

bind() agit localement, c'est-à-dire qu'il lie la fin de la connexion sur la machine sur laquelle il est appelé, à l'adresse demandée et vous attribue le port demandé. Il le fait indépendamment du fait que cette machine sera un client ou un serveur. connect() établit une connexion avec un serveur, c'est-à-dire qu'il se connecte à l'adresse et au port demandés sur le serveur, à partir d'un client. Ce serveur aura presque certainement appelé bind() avant listen() afin de vous permettre de savoir sur quelle adresse et sur quel port vous connecter avec connect().

Si vous n'appelez pas bind(), un port et une adresse sont affectés implicitement et liés pour vous à la machine locale lorsque vous appelez connect() (client) ou listen() (serveur). Cependant, c'est un effet secondaire des deux, pas leur but. Un port attribué de cette manière est éphémère.

Un point important ici est que le client n'a pas besoin d'être lié, car les clients se connectent aux serveurs. Ainsi, le serveur connaît l'adresse et le port du client même si vous utilisez un port éphémère, plutôt que de vous lier à quelque chose de spécifique. D'autre part, bien que le serveur puisse appeler listen() sans appeler bind(), il doit dans ce cas découvrir le port éphémère qui lui est attribué et le communiquer à tout client auquel il souhaite se connecter.

Je suppose que lorsque vous mentionnez connect() vous vous intéressez à TCP, cela concerne également UDP, où vous n'appelez pas bind() avant la première sendto() (UDP n'a pas de connexion) et provoque également un port et une adresse à attribuer et à lier implicitement. Une fonction que vous ne pouvez pas appeler sans liaison est recvfrom(), ce qui renverra une erreur, car sans port attribué et adresse associée, il n'y a rien à recevoir (ou trop, en fonction de la manière dont vous interprétez l'absence de liaison). ).

4
pjcard

Trop long; Ne pas lire: La différence est de savoir si la source (locale) ou l'adresse/le port de destination est en cours de définition. En résumé, bind() a défini la source et connect() a défini la destination. Indépendamment de TCP ou UDP.

bind()

bind() définit l'adresse locale (source) du socket. C'est l'adresse où les paquets sont reçus. Les paquets envoyés par le socket portent ceci en tant qu’adresse source, ainsi l’autre hôte saura où renvoyer ses paquets.

Si la réception n'est pas nécessaire, l'adresse source du socket est inutile. Des protocoles tels que TCP nécessitent une réception activée pour pouvoir être envoyés correctement, car l'hôte de destination renvoie une confirmation lorsqu'un ou plusieurs paquets sont arrivés (c'est-à-dire un accusé de réception).

connect()

  • TCP a un état "connecté". connect() déclenche le code TCP pour tenter d'établir une connexion avec l'autre côté.
  • UDP n'a pas d'état "connecté". connect() définissez uniquement une adresse par défaut sur laquelle les paquets sont envoyés sans adresse spécifiée. Lorsque connect() n'est pas utilisé, vous devez utiliser sendto() ou sendmsg() avec l'adresse de destination.

Lorsque connect() ou une fonction d'envoi est appelée et qu'aucune adresse n'est liée, Linux lie automatiquement le socket à un port aléatoire. Pour plus de détails techniques, consultez inet_autobind() dans le code source du noyau Linux.

Notes de côté

  • listen() est TCP uniquement.
  • Dans la famille AF_INET , l'adresse source ou de destination du socket (struct sockaddr_in) est composée d'une adresse IP (voir en-tête IP ), et TCP ou port UDP (voir TCP et UDP en-tête).