2014-11-19 5 views
66

Entrambe le chiamate di sistema "associa" il descrittore di file socket a un indirizzo (tipicamente una combinazione di ip/port) sia per le chiamate di sistema connect() e bind(). I loro prototipi sono come: -socket connect() vs bind()

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

e

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

Qual è la differenza esatta tra 2 chiamate? Quando si dovrebbe usare connect() e quando bind()?

In particolare, in alcuni codici client server di esempio, è stato rilevato che il client utilizza connect() e il server sta utilizzando la chiamata bind(). La ragione non mi era del tutto chiara.

+8

In una frase: bind è all'indirizzo locale, la connessione è all'indirizzo remoto. – SHR

risposta

126

Per rendere migliore comprensione, lascia scoprire dove esattamente legare e collegare entra in foto,

seguito al posizionamento di due chiamate, come chiarito dalla Sourav,

bind() associa la presa con il suo indirizzo locale [ecco perché il lato server si collega, in modo che i client possano usare quell'indirizzo per connettersi al server.] connect() è usato per connettersi a un indirizzo [server] remoto, ecco perché è lato client, connetti [leggi come : connessione al server] è usato.

Non possiamo usarli in modo intercambiabile (anche quando abbiamo client/server sulla stessa macchina) a causa di ruoli specifici e dell'implementazione corrispondente.

Raccomanderò inoltre di correlare queste chiamate all'handshake TCP/IP.

enter image description here

Quindi, che invierà SYN qui, sarà connect(). Mentre bind() viene utilizzato per definire il punto finale della comunicazione.

Spero che questo aiuti !!

+0

grazie fratello. Con lo schema tutto può essere celato velocemente. Puoi dire qual è la differenza qui, se usiamo udp? – apm

+6

accept()
deve essere spostato sotto il blocco
fino alla connessione dal client – tschodt

24

L'unico rivestimento:bind() per l'indirizzo, connect() per l'indirizzo remoto.

Citando dalla pagina man di bind()

bind() assegna l'indirizzo indicato dal addr alla presa a cui si riferisce il sockfd descrittore di file. addrlen specifica la dimensione, in byte, della struttura dell'indirizzo indicata da addr. Tradizionalmente, questa operazione è chiamata "assegnazione di un nome a un socket".

e, dal medesimo per connect()

Il connect() chiamata di sistema collega la presa a cui si riferisce il descrittore di file sockfd all'indirizzo specificato da addr.

Per chiarire,

  • bind() associa la presa con il suo indirizzo locale [ecco perché lato server bind s, in modo che i clienti possono utilizzare questo indirizzo per collegare al server.]
  • connect() viene utilizzato per connettersi a un indirizzo [server] remoto, ovvero perché viene utilizzato il lato client, connect [leggi come: connect to server].
+0

Quindi, ad esempio, se il server e il processo client vengono eseguiti sulla stessa macchina, possono essere utilizzati in modo intercambiabile? –

+0

@SiddharthaGhosh No. Forse il client e il server si trovano sulla stessa macchina, ma sono ** processi ** diversi, giusto? Entrambe le API hanno il proprio scopo. Non sono mai "intercambiabili" –

+0

Cosa si intende esattamente per locale e remoto in questo contesto? –

4

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

connect():

Il connect() chiamata di sistema collega una presa, identificato dal suo descrittore di file, ad un host remoto specificato da indirizzo dell'host nel lista di argomenti.

Alcuni tipi di socket sono socket di protocollo datagramma utente senza connessione. Per questi socket, connect assume un significato speciale: il target predefinito per l'invio e la ricezione dei dati viene impostato sull'indirizzo dato, consentendo l'uso di funzioni come send() e recv() su socket senza connessione.

connect() restituisce un numero intero che rappresenta il codice di errore: 0 rappresenta il successo, mentre -1 rappresenta un errore.

bind():

bind() assegna un socket a un indirizzo. Quando un socket viene creato utilizzando socket(), viene fornita solo una famiglia di protocolli, ma non viene assegnato un indirizzo. Questa associazione con un indirizzo deve essere eseguita con la chiamata di sistema bind() prima che il socket possa accettare connessioni ad altri host. bind() accetta tre argomenti:

sockfd, un descrittore che rappresenta il socket per eseguire il bind. my_addr, un puntatore a una struttura sockaddr che rappresenta l'indirizzo a cui collegarsi. addrlen, un campo socklen_t che specifica la dimensione della struttura sockaddr. Bind() restituisce 0 in caso di successo e -1 se si verifica un errore.

Esempi: 1. ) Usando Collegare

#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 Esempio:

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

Spero che chiarisce la differenza

EDIT: Si prega di notare che la presa tipo che dichiari dipenderà da ciò che richiedi, questo è estremamente importante

4

bind indica al processo in esecuzione di richiedere una porta. Vale a dire, dovrebbe legarsi alla porta 80 e ascoltare le richieste in entrata. con bind, il tuo processo diventa un server. quando usi connect, comunichi al tuo processo di connettersi a una porta GIÀ in uso. il tuo processo diventa un cliente. la differenza è importante: bind vuole una porta che non è in uso (in modo che possa rivendicarla e diventare un server) e connettersi vuole una porta già in uso (in modo che possa connettersi e parlare al server)

1

penso che aiuterebbe la vostra comprensione se si pensa di connect() e listen() come controparti, piuttosto che connect() e bind().La ragione di ciò è che puoi chiamare o omettere lo bind() prima di entrambi, anche se raramente è una buona idea chiamarlo prima dello connect() o non chiamarlo prima dello listen().

Se aiuta a pensare in termini di server e client, è listen() che è il segno distintivo del primo e connect() quest'ultimo. bind() può essere trovato - o non trovato - su entrambi.

Se assumiamo che il nostro server e il nostro client si trovano su macchine diverse, diventa più facile capire le varie funzioni.

bind() atti locali, vale a dire che vincola la fine della connessione sulla macchina su cui è chiamato, all'indirizzo richiesto e assegna la porta richiesta all'utente. Lo fa indipendentemente dal fatto che quella macchina sarà un client o un server. connect() avvia una connessione a un server, vale a dire che si connette all'indirizzo e alla porta richiesti sul server, da un client. Il server avrà quasi certamente chiamato bind() prima di listen(), in modo che tu possa sapere su quale indirizzo e porta collegarsi ad esso usando connect().

Se non si chiama bind(), una porta e un indirizzo verranno assegnati e collegati in modo implicito sulla macchina locale quando si chiama connect() (client) o listen() (server). Tuttavia, questo è un effetto collaterale di entrambi, non il loro scopo. Una porta assegnata in questo modo è effimera.

Un punto importante qui è che il client non ha bisogno di essere associato, perché i client si connettono ai server, e quindi il server conoscerà l'indirizzo e la porta del client anche se si sta utilizzando una porta temporanea, piuttosto che vincolante per qualcosa di specifico. D'altra parte, sebbene il server possa chiamare listen() senza chiamare bind(), in quello scenario dovranno scoprire la porta temporanea assegnata e comunicarlo a qualsiasi client a cui desidera connettersi.

presumo come si parla connect() siete interessati a TCP, ma questo porta anche verso UDP, dove non chiamare bind() prima del primo sendto() (UDP è il collegamento-meno) fa sì che anche una porta e l'indirizzo da assegnare implicitamente e legato. Una funzione che non è possibile chiamare senza il binding è recvfrom(), che restituirà un errore, poiché senza una porta assegnata e un indirizzo associato, non vi è nulla da ricevere (o troppo, a seconda di come si interpreta l'assenza di un'associazione).