C ++ Linux getpeername和getsockname仅返回端口

时间:2011-01-09 11:41:56

标签: c++ linux system-calls

在我的Linux C ++应用程序中,我使用的是getpeername和getsockname。 在操作系统上启用IPv6时,getpeername和getsockname都只返回端口!

代码:

int GetSockAndPeer(int sock) 
{     
   struct sockaddr_storage ss;    
   socklen_t salen = sizeof(ss);    
   struct sockaddr *sa;   
   struct addrinfo hints, *paddr, *paddrp;     
   sa = (struct sockaddr *)&ss;   
   if (getpeername(sock, sa, &salen) != 0) 
   {           
       return -1;     
   } 
   if (getsockname(sock, sa, &salen) != 0) 
   {           
       return -1;     
   } 
} 

在sa_data中系统调用sa_data [0]和sa_data [1](表示端口)之后的变量保持。所有其他字节都是0;

任何帮助???

2 个答案:

答案 0 :(得分:1)

RFC2553相关,您必须使用IN6_IS_ADDR_V4MAPPEDIN6_IS_ADDR_V4COMPAT宏来确定您的socket_storage内是否有可用的IPv4信息,或者确切地说是sockaddr_in6结构:

struct sockaddr_in6 {
    sa_family_t     sin6_family;    /* AF_INET6 */
    in_port_t       sin6_port;      /* transport layer port # */
    uint32_t        sin6_flowinfo;  /* IPv6 traffic class & flow info */
    struct in6_addr sin6_addr;      /* IPv6 address */
    uint32_t        sin6_scope_id;  /* set of interfaces for a scope */
};

如果两个宏都返回true,则IPv4地址位于sockaddr_in6.sin6_addr[12-15]

printf("%u.%u.%u.%u\n", sockaddr_in6.sin6_addr[12], sockaddr_in6.sin6_addr[13], \
                        sockaddr_in6.sin6_addr[14], sockaddr_in6.sin6_addr[15])

答案 1 :(得分:0)

重要的是要记住,除非连接套接字(或者,对于无连接套接字,已传输数据),可能没有任何与套接字关联的本地或远程IP地址。

假设计算机是多宿主的,并且具有本地和Internet IP地址。甚至可能是多个本地网络IP地址。如果您选择将套接字绑定到“任何”本地地址(使用INADDR_ANY类型标志),或者从不首先调用bind(),则套接字API没有与套接字关联的单个本地IP地址,只是最多的端口号。当您在套接字上调用connect()时,系统会根据您要连接的人选择要使用的本地IP。因此,如果通过Internet连接到计算机,则Internet IP与套接字关联,如果连接到本地网络上的计算机,则使用LAN IP地址。

因此,在使用getsockname()之前,可以确保将connect()连接到远程计算机或bind()到特定的本地IP。我想知道启用IPv6是否会导致您的计算机看到多个可能使用的本地IP。显然你很多都被连接到机器上以使用getpeername()。