socket connect()vs bind()

时间:2014-11-19 10:49:50

标签: c sockets network-programming

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

两次通话之间的确切区别是什么?应该何时使用connect()bind()

具体来说,在某些示例服务器客户端代码中,发现客户端正在使用connect()且服务器正在使用bind()调用。理由并不完全清楚。

6 个答案:

答案 0 :(得分:181)

为了更好地理解,让我们找出完全绑定和连接的位置,

进一步定位两个电话,如Sourav澄清,

bind()将套接字与其本地地址相关联[这就是服务器端绑定的原因,以便客户端可以使用该地址连接到服务器。] connect()用于连接远程[服务器]地址,这就是客户端,连接[read as:connect to server]的原因。

由于具体的角色和相应的实现,我们不能互换使用它们(即使我们在同一台机器上有客户机/服务器)。

我将进一步建议关联这些调用TCP / IP握手。

enter image description here

那么,谁将在这里发送SYN,它将是connect()。而bind()用于定义通信端点。

希望这会有所帮助!!

答案 1 :(得分:38)

单行: bind()拥有地址,connect()为远程地址。

bind()

的手册页引用
  

bind()将addr指定的地址分配给文件描述符sockfd引用的套接字。 addrlen指定addr指向的地址结构的大小(以字节为单位)。传统上,此操作称为“为套接字分配名称”。

,同样适用于connect()

  

connect()系统调用将文件描述符sockfd引用的套接字连接到addr指定的地址。

澄清,

  • bind()将套接字与其本地地址相关联[这就是原因 服务器端bind,以便客户端可以使用该地址进行连接 到服务器。]
  • connect()用于连接远程[服务器]地址,即 为什么是客户端,连接[读取:连接到服务器]使用。

答案 2 :(得分:7)

来自维基百科http://en.wikipedia.org/wiki/Berkeley_sockets#bind.28.29

连接():

connect()系统调用将由其文件描述符标识的套接字连接到由参数列表中该主机的地址指定的远程主机。

某些类型的套接字是无连接的,最常见的是用户数据报协议套接字。对于这些套接字,connect具有特殊含义:发送和接收数据的默认目标设置为给定地址,允许在无连接套接字上使用send()和recv()等函数。

connect()返回一个表示错误代码的整数:0表示成功,而-1表示错误。

<强>绑定():

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

我希望澄清差异

请注意,您声明的套接字类型取决于您的需求,这非常重要

答案 3 :(得分:6)

bind告诉正在运行的进程声明一个端口。它应该将自己绑定到端口80并监听请求。使用bind,您的进程将成为服务器。当您使用connect时,您告诉您的进程连接到一个使用中的ALREADY端口。您的流程成为客户。区别很重要:bind需要一个未使用的端口(以便它可以声明它并成为服务器),并且connect需要一个已经在使用的端口(因此它可以连接到它并与服务器通信)

答案 4 :(得分:3)

如果您将connect()listen()视为对方,而不是connect()bind(),我认为这将有助于您理解。这样做的原因是你可以在之前打电话或省略bind(),虽然在connect()之前调用它很少是个好主意,或者在listen()之前调用它很少。

如果考虑服务器和客户端是有帮助的,那么listen()是前者的标志,connect()是后者。 bind()可以找到 - 或者找不到 - 。

如果我们假设我们的服务器和客户端在不同的机器上,那么理解各种功能就变得更容易了。

bind()在本地起作用,也就是说它将调用它的机器上的连接的末端绑定到请求的地址,并为您分配所请求的端口。无论该机器是客户端还是服务器,它都会这样做。 connect()启动与服务器的连接,也就是说它从客户端连接到服务器上请求的地址和端口。该服务器几乎肯定会在bind()之前调用listen(),以便您能够使用connect()知道要连接到哪个地址和端口。

如果您不打电话给bind(),当您拨打connect()(客户端)或{{1}时,您将在本地计算机上隐式分配和绑定端口和地址(服务器)。然而,这是两者的副作用,而不是它们的目的。以这种方式分配的端口是短暂的。

这里的一个重点是客户端不需要绑定,因为客户端连接到服务器,因此即使您使用的是临时端口,服务器也会知道客户端的地址和端口,而不是绑定到特定的东西。另一方面,虽然服务器可以在不调用listen()的情况下调用listen(),但在这种情况下,他们需要发现其分配的临时端口,并将其传达给它想要连接到它的任何客户端。

我假设您提及bind()您对TCP感兴趣,但这也会延续到UDP,而不是在第一个connect()之前调用bind()(UDP是连接) -less)还会导致隐式分配和绑定端口和地址。你无法在没有绑定的情况下调用的一个函数是sendto(),它将返回一个错误,因为没有指定的端口和绑定地址,没有任何东西可以接收(或者太多,取决于你如何解释没有绑定)。

答案 5 :(得分:1)

太长;不读:区别在于是否设置了源(本地)或目标地址/端口。简而言之,bind()设置了源,connect()设置了目的地。不管是TCP还是UDP。

bind()

bind()设置套接字的本地(源)地址。这是接收数据包的地址。套接字发送的数据包将其作为源地址,因此另一台主机将知道将其数据包发送回何处。

如果不需要接收,则套接字源地址无用。像TCP这样的协议需要启用接收才能正确发送,因为目标主机在一个或多个数据包到达时会发回一个确认(即确认)。

connect()

  • TCP处于“连接”状态。 connect()触发TCP代码以尝试建立与另一端的连接。
  • UDP没有“连接”状态。 connect()仅在未指定地址的情况下才将默认地址设置为将数据包发送到的地址。不使用connect()时,必须使用包含目标地址的sendto()sendmsg()

当调用connect()或send函数时,并且没有地址绑定,Linux会自动将套接字绑定到随机端口。有关技术细节,请查看Linux内核源代码中的inet_autobind()

旁注

  • listen()仅是TCP。
  • AF_INET 系列中,套接字的源地址或目标地址(struct sockaddr_in)由IP地址(请参见IP header)和TCP或UDP端口(请参见{ {3}}和TCP标头)。