获取Socket使用的本地端口

时间:2015-06-02 13:10:06

标签: c sockets winsock

我需要获取(客户端)套接字使用的本地端口。

据我了解,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

4 个答案:

答案 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。