C语言 套接字连接()与绑定()

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27014955/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 11:34:11  来源:igfitidea点击:

socket connect() vs bind()

csocketsnetwork-programming

提问by Siddhartha Ghosh

Both connect()and bind()system calls 'associate' the socket file descriptor to an address (typically an ip/port combination). Their prototypes are like:-

connect()bind()系统调用都将套接字文件描述符“关联”到一个地址(通常是一个 ip/端口组合)。他们的原型是这样的:-

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

and

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

What is the exact difference between 2 calls? When should one use connect()and when bind()?

2个电话之间的确切区别是什么?什么时候应该用connect(),什么时候用bind()

Specifically, in some sample server client codes, found that client is using connect()and server is using the bind()call. Reason was not fully clear to me.

具体来说,在一些示例服务器客户端代码中,发现客户端正在使用connect()和服务器正在使用bind()调用。原因对我来说并不完全清楚。

回答by Jain Rach

To make understanding better , lets find out where exactly bind and connect comes into picture,

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

Further to positioning of two calls , as clarified by Sourav,

进一步定位两个调用,如 Sourav 所澄清,

bind() associates the socket with its local address [that's why server side binds, so that clients can use that address to connect to server.] connect() is used to connect to a remote [server] address, that's why is client side, connect [read as: connect to server] is used.

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

We cannot use them interchangeably (even when we have client/server on same machine) because of specific roles and corresponding implementation.

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

I will further recommend to correlate these calls TCP/IP handshake .

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

enter image description here

在此处输入图片说明

So , who will send SYN here , it will be connect() . While bind() is used for defining the communication end point.

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

Hope this helps!!

希望这可以帮助!!

回答by Sourav Ghosh

The one liner :bind()to own address, connect()to remote address.

一班:bind()到自己的地址,connect()到远程地址。

Quoting from the man page of bind()

引自手册页 bind()

bind() assigns the address specified by addr to the socket referred to by the file descriptor sockfd. addrlen specifies the size, in bytes, of the address structure pointed to by addr. Traditionally, this operation is called "assigning a name to a socket".

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

and, from the same for connect()

并且,从相同的 connect()

The connect() system call connects the socket referred to by the file descriptor sockfd to the address specified by addr.

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

To clarify,

澄清,

  • bind()associates the socket with its local address [that's why server side binds, so that clients can use that address to connect to server.]
  • connect()is used to connect to a remote [server] address, that's why is client side, connect [read as: connect to server] is used.
  • bind()将套接字与其本地地址相关联 [这就是为什么服务器端binds,以便客户端可以使用该地址连接到服务器。]
  • connect()用于连接到远程[服务器]地址,这就是为什么在客户端,使用connect [读作:连接到服务器]。

回答by Philipp Murry

bind tells the running process to claim a port. i.e, it should bind itself to port 80 and listen for incomming requests. with bind, your process becomes a server. when you use connect, you tell your process to connect to a port that is ALREADY in use. your process becomes a client. the difference is important: bind wants a port that is not in use (so that it can claim it and become a server), and connect wants a port that is already in use (so it can connect to it and talk to the server)

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

回答by pjcard

I think it would help your comprehension if you think of connect()and listen()as counterparts, rather than connect()and bind(). The reason for this is that you can call or omit bind()before either, although it's rarely a good idea to call it before connect(), or not to call it before listen().

我认为,如果您将connect()andlisten()视为对应物,而不是connect()and ,这将有助于您的理解bind()。这样做的原因是您可以调用或省略bind()before ,尽管在 before 调用它connect()或不在before 调用它很少是一个好主意listen()

If it helps to think in terms of servers and clients, it is listen()which is the hallmark of the former, and connect()the latter. bind()can be found - or not found - on either.

如果从服务器和客户端的角度来思考有帮助,那就是listen()前者和connect()后者的标志。bind()可以在任何一个上找到 - 或找不到。

If we assume our server and client are on different machines, it becomes easier to understand the various functions.

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

bind()acts locally, which is to say it binds the end of the connection on the machine on which it is called, to the requested address and assigns the requested port to you. It does that irrespective of whether that machine will be a client or a server. connect()initiates a connection to a server, which is to say it connects to the requested address and port on the server, from a client. That server will almost certainly have called bind()prior to listen(), in order for you to be able to know on which address and port to connect to it with using connect().

bind()在本地操作,也就是说,它将调用它的机器上的连接末端绑定到请求的地址,并将请求的端口分配给您。不管那台机器是客户端还是服务器,它都会这样做。connect()启动到服务器的连接,也就是说它从客户端连接到服务器上请求的地址和端口。该服务器几乎肯定会在此bind()之前调用过listen(),以便您能够知道使用connect().

If you don't call bind(), a port and address will be implicitly assigned and bound on the local machine for you when you call either connect()(client) or listen()(server). However, that's a side effect of both, not their purpose. A port assigned in this manner is ephemeral.

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

An important point here is that the client does not need to be bound, because clients connect to servers, and so the server will know the address and port of the client even though you are using an ephemeral port, rather than binding to something specific. On the other hand, although the server could call listen()without calling bind(), in that scenario they would need to discover their assigned ephemeral port, and communicate that to any client that it wants to connect to it.

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

I assume as you mention connect()you're interested in TCP, but this also carries over to UDP, where not calling bind()before the first sendto()(UDP is connection-less) also causes a port and address to be implicitly assigned and bound. One function you cannot call without binding is recvfrom(), which will return an error, because without an assigned port and bound address, there is nothing to receive from (or too much, depending on how you interpret the absence of a binding).

我假设你提到connect()你对 TCP 感兴趣,但这也会延续到 UDP,在bind()第一个之前不调用sendto()(UDP 是无连接的)也会导致端口和地址被隐式分配和绑定。没有绑定就不能调用的一个函数是recvfrom(),它会返回一个错误,因为如果没有分配的端口和绑定地址,就没有什么可以接收的(或者太多,取决于你如何解释没有绑定的情况)。

回答by Khan

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

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

connect():

连接():

The connect() system call connects a socket, identified by its file descriptor, to a remote host specified by that host's address in the argument list.

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

Certain types of sockets are connectionless, most commonly user datagram protocol sockets. For these sockets, connect takes on a special meaning: the default target for sending and receiving data gets set to the given address, allowing the use of functions such as send() and recv() on connectionless sockets.

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

connect() returns an integer representing the error code: 0 represents success, while -1 represents an error.

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

bind():

绑定():

bind() assigns a socket to an address. When a socket is created using socket(), it is only given a protocol family, but not assigned an address. This association with an address must be performed with the bind() system call before the socket can accept connections to other hosts. bind() takes three arguments:

bind() 将套接字分配给地址。当使用 socket() 创建套接字时,它只被赋予一个协议族,但没有分配地址。在套接字可以接受与其他主机的连接之前,必须使用 bind() 系统调用执行与地址的这种关联。bind() 接受三个参数:

sockfd, a descriptor representing the socket to perform the bind on. my_addr, a pointer to a sockaddr structure representing the address to bind to. addrlen, a socklen_t field specifying the size of the sockaddr structure. Bind() returns 0 on success and -1 if an error occurs.

sockfd,表示要执行绑定的套接字的描述符。my_addr,指向表示要绑定到的地址的 sockaddr 结构的指针。addrlen,一个指定 sockaddr 结构大小的 socklen_t 字段。Bind() 在成功时返回 0,如果发生错误则返回 -1。

Examples: 1.)Using Connect

示例: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, '
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);
    }
', 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 Example:

2.)绑定示例:

##代码##

I hope that clarifies the difference

我希望能澄清区别

Please note that the socket type that you declare will depend on what you require, this is extremely important

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

回答by Ricardo Biehl Pasquali

Too Long; Don't Read: The difference is whether the source (local) or the destination address/port is being set. In short, bind()set the source and connect()set the destination. Regardless of TCP or UDP.

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

bind()

bind()

bind()set the socket's local (source) address. This is the address where packets are received. Packets sent by the socket carry this as the source address, so the other host will know where to send back its packets.

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

If receive is not needed the socket source address is useless. Protocols like TCP require receiving enabled in order to send properly, as the destination host send back a confirmation when one or more packets have arrived (i.e. acknowledgement).

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

connect()

connect()

  • TCP has a "connected" state. connect()triggers the TCP code to try to establish a connection to the other side.
  • UDP has no "connected" state. connect()only set a default address to where packets are sent when no address is specified. When connect()is not used, sendto()or sendmsg()must be used containing the destination address.
  • TCP 具有“已连接”状态。connect()触发 TCP 代码尝试与另一端建立连接。
  • UDP 没有“连接”状态。connect()仅在未指定地址时将默认地址设置为发送数据包的位置。何时connect()不使用,sendto()sendmsg()必须使用包含目标地址。

When connect()or a send function is called, and no address is bound, Linux automatically bind the socket to a random port. For technical details, take a look at inet_autobind()in Linux kernel source code.

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

Side notes

旁注

  • listen()is TCP only.
  • In AF_INETfamily, the socket's source or destination address (struct sockaddr_in) is composed by an IP address (see IP header), and TCP or UDP port (see TCPand UDPheader).
  • listen()仅是 TCP。
  • AF_INET系列中,套接字的源地址或目标地址 ( struct sockaddr_in) 由 IP 地址(参见IP 标头)和 TCP 或 UDP 端口(参见TCPUDP标头)组成。