我在这里查看udp客户端示例: http://www.linuxhowtos.org/data/6/client_udp.c
摘要:
/* UDP client in the internet domain */
struct sockaddr_in server, from;
//...snipped
sock= socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) error("socket");
server.sin_family = AF_INET;
hp = gethostbyname(argv[1]);
if (hp==0) error("Unknown host");
bcopy((char *)hp->h_addr,
(char *)&server.sin_addr,
hp->h_length);
server.sin_port = htons(atoi(argv[2]));
length=sizeof(struct sockaddr_in);
//... snipped
n=sendto(sock,buffer,
strlen(buffer),0,(const struct sockaddr *)&server,length);
if (n < 0) error("Sendto");
n = recvfrom(sock,buffer,256,0,(struct sockaddr *)&from, &length);
if (n < 0) error("recvfrom");
//... snipped
我试图了解它如何知道从哪里接收消息。我知道何时调用sendto
时,会选择一个可用端口并将其嵌入udp消息中,并且服务器应用程序可以读取并回复它。客户端代码如何知道在该端口上接收消息?
此答案:https://stackoverflow.com/a/48245273/2748602表示调用sendto
函数时存在某种隐式绑定。它是如何工作的?实际上,它是否是具有一个随机可用端口号的绑定,而该端口号就像我曾经叫过bind
一样永久存在?似乎存在永久性的某些方面。只是对更多细节感兴趣。
答案 0 :(得分:1)
如果套接字未绑定,则是隐式绑定,因为所有数据包都必须同时承载两个源端口。因此,API假定,如果您对端口预先绑定的端口并不十分在意,则可以将套接字绑定到随机端口。而且,不幸的是,我不知道sendto
的实现细节,我可以提供一些官方文档。
对于Linux,请从udp man page:
创建UDP套接字后,其本地和远程地址为 未指定。数据报可以使用sendto(2)或 sendmsg(2),带有有效的目标地址作为参数。什么时候 在套接字(默认目标)上调用connect(2) 设置了地址,现在可以使用send(2)或write(2)发送数据报 而不指定目标地址。仍然有可能 通过将地址传递到sendto(2)来发送到其他目的地,或者 sendmsg(2)。 为了接收数据包,可以将套接字绑定到 首先使用bind(2)本地地址。 *否则,套接字层 将自动分配超出定义范围的空闲本地端口 通过/ proc / sys / net / ipv4 / ip_local_port_range并将套接字绑定到 INADDR_ANY 。
对于Windows,是Winsock 2's sendto文档的摘录:
如果套接字未绑定,则将唯一值分配给本地 系统关联,然后将套接字标记为绑定。如果 套接字已连接,getsockname函数可用于 确定与套接字关联的本地IP地址和端口。
答案 1 :(得分:0)
...调用sendto函数时,存在某种隐式绑定。它是如何工作的?实际上,它是一个具有随机可用端口号的绑定,该端口号是否像我所说的bind一样永久不变?
ip_local_port_range (since Linux 2.2)
This file contains two integers that define the default local
port range allocated to sockets that are not explicitly bound
to a port number—that is, the range used for ephemeral ports.
An ephemeral port is allocated to a socket in the following
circumstances:
* the port number in a socket address is specified as 0 when calling bind(2);
* listen(2) is called on a stream socket that was not previously bound;
* connect(2) was called on a socket that was not previously bound;
* sendto(2) is called on a datagram socket that was not previously bound.