【发布时间】:2021-04-22 20:23:02
【问题描述】:
阅读https://www.amazon.com/Unix-Network-Programming-Sockets-Networking/dp/0131411551,章节
8.14 使用 UDP 确定传出接口
已连接的 UDP 套接字也可用于确定将要发送的传出接口 用于特定目的地。这是因为连接的副作用 应用于 UDP 套接字时的功能:内核选择本地 IP 地址 (假设该进程尚未调用 bind 来显式分配 this)。这个当地 通过在路由表中搜索目标 IP 地址来选择 IP 地址,并且 然后使用生成的接口的主 IP 地址。
如果我尝试运行示例 (udpcli01.c):
#define BSIZE 256
#define SERV_PORT 9877
typedef struct sockaddr SA;
//argv[1] = ip address
int main(int argc, char **argv)
{
int sockfd;
socklen_t servlen, clilen;
struct sockaddr_in cliaddr, servaddr;
char ip[BSIZE];
if (argc < 2)
{
die("usage: %s <ip>\n", argv[0]);
}
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
servlen = sizeof(servaddr);
memset(&servaddr, 0, servlen);
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
connect(sockfd, (SA *)&servaddr, servlen);
clilen = sizeof(clilen);
if (getsockname(sockfd, (SA *)&cliaddr, &clilen) < 0)
{
perror("getsockname");
}
inet_ntop(AF_INET, &cliaddr, ip, BSIZE);
printf("address %s:%hd\n", ip, cliaddr.sin_port);
}
现在如果我在一个终端(地址INADDR_ANY和端口9877)运行服务器,然后运行上面的客户端:
terminal 1:
$ ./udpserv01
terminal 2:
$ #I will try localhost first
$ ./udpcli01 127.0.0.1
address 2.0.178.211:-11342
$ #did not work, now my host ip 10.0.0.11
$ ./udpcli01 10.0.0.11
address 2.0.193.86:22209
即使客户端在打印其地址和端口之前连接到正在侦听的服务器,我总是会得到一些垃圾。如果我试图打印服务器地址和端口,那么它会起作用(也就是说,它会分别打印127.0.0.1:9877 和10.0.0.11:9877 -> 我已经尝试过了)。所以我知道inet_ntop 工作正常并且还获得了端口号。那么客户端的问题在哪里呢?内核真的按照书上的说法在connect()上分配地址和端口吗?如果是这样,为什么我的示例会打印随机垃圾?
uname -a:
Linux Shepherd 5.8.0-36-generic #40-Ubuntu SMP Tue Jan 5 21:54:35 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
【问题讨论】:
-
POSIX documentation for
connect()确实声明:“如果套接字尚未绑定到本地地址,connect()应将其绑定到一个地址,除非套接字的地址族是AF_UNIX,是未使用的本地地址。”所以你似乎发现了一些错误。您使用的是什么操作系统? 所有分配给您系统的 IP 地址是什么?并且端口值在网络字节顺序中为unsigned short。 -
@AndrewHenle 查看编辑。 1)使用linux,2)我不知道如何找出分配给我的系统的地址。 3) 是的,我的错误,我忘记使用
ntohs()来转换端口。但是地址反正是垃圾