我需要获取(客户端)套接字使用的本地端口。
据我了解,Windows Sockets performs an implicit bind function call
因此getsockname()
之后的sendto()
应该提供指定的端口。但是,它始终将0设置为端口号。我错过了什么吗?
前:
if (sendto(sockfd, ...) != SOCKET_ERROR)
printf("Sent\n");
if (getsockname(sockfd, (struct sockaddr*)&sin, &sinlen) != SOCKET_ERROR)
printf("port = %u\n", ntohs(sin.sin_port);
else
printf("Error");
//result: Sent, port = 0
答案 0 :(得分:0)
我在示例代码中看到的唯一歧义是您在调用之前分配给sinlen
的大小。 (您没有显示)如果您使用的是 winsock ,则应对其进行定义并指定int sinlen = sizeof(sin);
我在我的系统上使用了这段代码,它为我连接的端口返回一个非零值:
struct sockaddr_in sin;
int len = sizeof(sin);
if (getsockname(sock, (struct sockaddr *)&sin, &len) == -1)
//handle error
else
printf("port number %d\n", ntohs(sin.sin_port));
顺便说一句, ntohs function 函数以主机字节顺序返回值。如果[sin.sin_port
]已经是主机字节顺序,那么此函数将反转它。由 [your] 应用程序决定是否必须反转字节顺序。 [括号中的文字是我的重点]
回答 评论问题( getsockname() ):
getsockname()
的函数原型:
int getsockname(
_In_ SOCKET s,
_Out_ struct sockaddr *name,
_Inout_ int *namelen //int, not socklen_t
);
有关 socklen_t
的更多讨论 编辑 (解决重新设置套接字的可能方法,无需重启PC。)
如果winsock API调用停止以预测方式工作,则可以使用 WSAStartup 和 {{3重新启动套接字而无需重新启动PC (请参阅WSAStartup链接底部的代码示例)
答案 1 :(得分:0)
重启计算机后问题解决了。关于实际原因仍然未知,但此时我很高兴它能够工作。
如果有人想要解决问题而不用重启(对于未来的读者),请随时发布。
答案 2 :(得分:0)
你说你想知道LOCAL端口,但你的线路
sendto(sockfd, ...)
暗示sockfd是REMOTE描述符。因此,您以后的代码可能会向您提供有关REMOTE端口的信息,而不是LOCAL端口。 '插座'不是两端,意味着一个联系。套接字是一端,表示连接一端的IP和端口号。 getsockname()的第一个参数不是引用或指针,因此它不是函数的输出,而是输入。您告诉该函数使用您刚刚发送到的相同套接字描述符,即。远程的。
格式化错误。 ntohs()返回unsigned short,因此格式应为%hu,而不是%u或%d。如果你抓住太多字节,它们就不是端口。
答案。使用sendto()后,尝试使用gethostname(),然后在返回的名称上使用getaddrinfo()。注意:您获取的addrinfo结构将为您提供struct sockaddr指针,您需要将其重新转换为struct sockaddr_in指针以访问本地端口号。
答案 3 :(得分:0)
要查找内核在发出sendto()函数时梦寐以求的本地端口号,也许您可以编写一个例程来解析(gnu linux)命令's'或'netstat'的输出。 (不确定这些是否与POSIX兼容。)或者,如果您有权限,也许可以访问/ proc / net。