2

我已经看到了两个示例,它们说明了客户端套接字如何从服务器接收消息。

示例 1:

服务器代码 http://man7.org/tlpi/code/online/book/sockets/ud_ucase_sv.c.html

客户端代码 http://man7.org/tlpi/code/online/book/sockets/ud_ucase_cl.c.html

客户端程序创建一个套接字并将该套接字绑定到一个地址,以便服务器可以发送它的回复。

if (bind(sfd, (struct sockaddr *) &claddr, sizeof(struct sockaddr_un)) == -1)
    errExit("bind"); // snippet from ud_ucase_cl.c

示例 2:

服务器代码 http://man7.org/tlpi/code/online/book/sockets/i6d_ucase_sv.c.html

客户端代码 http://man7.org/tlpi/code/online/book/sockets/i6d_ucase_cl.c.html

在示例 2 中,客户端代码没有将其套接字与地址绑定。

问题

客户端代码是否需要将套接字与地址绑定才能从服务器接收消息?

为什么在第一个示例中,我们必须将客户端套接字与地址绑定,为什么在第二个示例中不必?

4

3 回答 3

1

对于客户端(TCP)或发送者(UDP),调用bind()是可选的;这是一种指定接口的方法。假设您有两个接口,它们都可以路由到您的目的地:

eth0: 10.1.1.100/24
eth1: 10.2.2.100/24

route: 10.1.1.0/24 via 10.2.2.254  # router for eth1
       0.0.0.0     via 10.1.1.254  # general router

现在,如果您只是说connect()to 12.34.56.78,您不知道哪个本地接口提供连接的本地端。通过首先调用bind(),您可以将其具体化。

对于 UDP 流量也是如此:如果没有bind()ing,您sendto()将使用随机源地址和端口,但bind()您需要指定源。

于 2011-08-01T13:09:10.927 回答
1

不同之处在于第socket family一个示例使用AF_UNIX,而第二个示例使用AF_INET6。根据Stevens UNP,您需要显式地bind指定 Unix 客户端套接字的路径名,以便服务器具有可以向其发送回复的路径名:

... 将数据报发送到未绑定的 Unix 域数据报套接字不会将路径名隐式绑定到套接字。因此,如果我们省略这一步,服务器对 ... 的调用将recvfrom返回一个空路径名 ...

套接字不需要这样做,INET{4,6}因为它们是“自动绑定”到临时端口的。

于 2011-08-01T13:54:38.767 回答
1

如果您在连接/发送之前没有绑定 AF_INET/AF_INET6 客户端套接字,TCP/IP 堆栈会自动将其绑定到出站地址上的临时端口。

与此不同的是,UNIX 域套接字(AF_UNIX)在发送时不会自动绑定,因此您可以通过 SOCK_DGRAM 发送消息但无法得到任何回复。

于 2011-08-01T13:56:20.723 回答