I have seen two examples that illustrate how the client socket can receive messages from server.
我已经看到两个示例,它们演示了客户端套接字如何从服务器接收消息。
Example 1:
示例1:
server code http://man7.org/tlpi/code/online/book/sockets/ud_ucase_sv.c.html
服务器代码http://man7.org/tlpi/code/online/book/sockets/ud_ucase_sv.c.html
client code http://man7.org/tlpi/code/online/book/sockets/ud_ucase_cl.c.html
客户端代码http://man7.org/tlpi/code/online/book/sockets/ud_ucase_cl.c.html
The client program creates a socket and binds the socket to an address, so that the server can send its reply.
客户端程序创建一个套接字并将套接字绑定到一个地址,这样服务器就可以发送它的回复。
if (bind(sfd, (struct sockaddr *) &claddr, sizeof(struct sockaddr_un)) == -1)
errExit("bind"); // snippet from ud_ucase_cl.c
Example 2:
示例2:
server code http://man7.org/tlpi/code/online/book/sockets/i6d_ucase_sv.c.html
服务器代码http://man7.org/tlpi/code/online/book/sockets/i6d_ucase_sv.c.html
client code http://man7.org/tlpi/code/online/book/sockets/i6d_ucase_cl.c.html
客户端代码http://man7.org/tlpi/code/online/book/sockets/i6d_ucase_cl.c.html
In example 2, client code doesn't bind its socket with an address.
在示例2中,客户端代码不使用地址绑定套接字。
Question:
问题:
Is it necessary for the client code to bind the socket with an address in order to receive message from server?
客户端代码是否需要用一个地址绑定套接字以接收来自服务器的消息?
Why in the first example, we have to bind the client socket with an address, why we don't have to in the second example?
为什么在第一个示例中,我们必须用一个地址绑定客户端套接字,为什么在第二个示例中不需要呢?
3 个解决方案
#1
1
The difference is the socket family
- first example uses AF_UNIX
, while the second does AF_INET6
. According to Stevens UNP you need to explicitly bind
pathname to Unix client socket so that the server has a pathname to which it can send its reply:
区别在于套接字家族—第一个示例使用AF_UNIX,而第二个示例使用AF_INET6。根据Stevens UNP,您需要显式地将路径名绑定到Unix客户端套接字,以便服务器有一个路径名,可以将其回复发送到:
... sending a datagram to an unbound Unix domain datagram socket does not implicitly bind a pathname to the socket. Therefore, if we omit this step, the server's call to
recvfrom
... returns a null pathname ...
This is not required for INET{4,6}
sockets since they are "auto-bound" to an ephemeral port.
这对于INET{4,6}套接字是不需要的,因为它们是“自动绑定”到临时端口的。
#2
1
For the client (TCP) or sender (UDP), calling bind()
is optional; it is a way to specify the interface. Suppose you have two interfaces, which are both routable to your destination:
对于客户端(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
Now if you just say connect()
to 12.34.56.78
, you don't know which local interface furnishes the local side of the connection. By calling bind()
first, you make this specific.
现在,如果您只是说connect()到12.34.56.78,您不知道哪个本地接口提供了连接的本地端。通过首先调用bind(),您可以使其变得特定。
The same is true for UDP traffic: Without bind()
ing, your sendto()
will use a random source address and port, but with bind()
you make the source specific.
UDP流量也是如此:没有bind()ing,您的sendto()将使用一个随机的源地址和端口,但是使用bind()可以使源变得特定。
#3
1
If you have not bound AF_INET/AF_INET6 client socket before connecting/sending something, TCP/IP stack will automatically bind it to ephemeral port on outbound address.
如果在连接/发送某些东西之前没有绑定AF_INET/AF_INET6客户端套接字,TCP/IP堆栈将自动将其绑定到出站地址上的临时端口。
Unlike this, UNIX domain sockets (AF_UNIX) do not automatically bind when sending, so you can send messages via SOCK_DGRAM but can't get any replies.
与此不同的是,UNIX域套接字(AF_UNIX)在发送时不会自动绑定,因此您可以通过SOCK_DGRAM发送消息,但不能得到任何答复。
#1
1
The difference is the socket family
- first example uses AF_UNIX
, while the second does AF_INET6
. According to Stevens UNP you need to explicitly bind
pathname to Unix client socket so that the server has a pathname to which it can send its reply:
区别在于套接字家族—第一个示例使用AF_UNIX,而第二个示例使用AF_INET6。根据Stevens UNP,您需要显式地将路径名绑定到Unix客户端套接字,以便服务器有一个路径名,可以将其回复发送到:
... sending a datagram to an unbound Unix domain datagram socket does not implicitly bind a pathname to the socket. Therefore, if we omit this step, the server's call to
recvfrom
... returns a null pathname ...
This is not required for INET{4,6}
sockets since they are "auto-bound" to an ephemeral port.
这对于INET{4,6}套接字是不需要的,因为它们是“自动绑定”到临时端口的。
#2
1
For the client (TCP) or sender (UDP), calling bind()
is optional; it is a way to specify the interface. Suppose you have two interfaces, which are both routable to your destination:
对于客户端(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
Now if you just say connect()
to 12.34.56.78
, you don't know which local interface furnishes the local side of the connection. By calling bind()
first, you make this specific.
现在,如果您只是说connect()到12.34.56.78,您不知道哪个本地接口提供了连接的本地端。通过首先调用bind(),您可以使其变得特定。
The same is true for UDP traffic: Without bind()
ing, your sendto()
will use a random source address and port, but with bind()
you make the source specific.
UDP流量也是如此:没有bind()ing,您的sendto()将使用一个随机的源地址和端口,但是使用bind()可以使源变得特定。
#3
1
If you have not bound AF_INET/AF_INET6 client socket before connecting/sending something, TCP/IP stack will automatically bind it to ephemeral port on outbound address.
如果在连接/发送某些东西之前没有绑定AF_INET/AF_INET6客户端套接字,TCP/IP堆栈将自动将其绑定到出站地址上的临时端口。
Unlike this, UNIX domain sockets (AF_UNIX) do not automatically bind when sending, so you can send messages via SOCK_DGRAM but can't get any replies.
与此不同的是,UNIX域套接字(AF_UNIX)在发送时不会自动绑定,因此您可以通过SOCK_DGRAM发送消息,但不能得到任何答复。