udp套接字sendto隐式绑定

udp socket sendto implicit bind

本文关键字:绑定 sendto 套接字 udp      更新时间:2023-10-16

我在这里查看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或其他什么一样?似乎有一些永恒的方面。只是对更多的细节感兴趣。

如果套接字未绑定,则是一个隐式绑定,因为所有数据包都必须同时携带一个源端口。因此,API假设,如果您事先对端口不够关心,无法绑定套接字,则它可以将套接字绑定到随机端口。不幸的是,虽然我不知道sendto的实现细节,但我可以提供一些官方文档。

对于Linux,来自udp手册页:

创建UDP套接字时,其本地和远程地址为未指明。可以使用sendto(2)或sendmsg(2),并将有效的目标地址作为参数。什么时候connect(2)在默认目的地套接字上调用地址已设置,数据报现在可以使用发送(2)或写入(2)发送而不指定目的地地址。仍然有可能通过将地址传递给sendto(2)发送到其他目的地,或sendmsg(2)为了接收数据包,套接字可以绑定到本地地址首先使用bind(2)*否则,套接字层将自动分配一个超出定义范围的可用本地端口通过/proc/sys/net/ipv4/ip_local_port_range并将套接字绑定到INADDR_ANY

对于Windows,Winsock 2的sendto:的文档片段

如果套接字未绑定,则会将唯一值分配给本地关联,然后套接字被标记为绑定。如果套接字已连接,getsockname函数可用于确定与套接字相关联的本地IP地址和端口。

。。。当调用sendto函数时,存在一种隐式绑定。它是如何工作的?它实际上是一个具有随机可用端口号的绑定吗?它是永久的,就像我调用了绑定或其他什么一样?

man ip(7):

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.