当客户端和服务器位于不同的机器上时,getsockname() 不会 return 正确地址

getsockname() doesn't return correct address when client and server are on separate machines

我有以下客户端和服务器:

客户:

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

int main( int argc, char **argv ){
    int sockfd;
    struct sockaddr_in servaddr;
    memset( &servaddr, 0, sizeof( servaddr ) );
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons( 2000 );
    inet_pton( AF_INET, argv[1], &(servaddr.sin_addr) );
    sockfd = socket( AF_INET, SOCK_STREAM, 0 );
    if( connect( sockfd, (struct sockaddr *) &servaddr, sizeof( servaddr ) ) == -1 ){
            perror( "Client connection error: " );
            exit( errno );
    }
    struct sockaddr_in addr[2];
    recv( sockfd, addr, sizeof( struct sockaddr_in ) * 2, 0 );
    char addr_str_cli[16];
    char addr_str_srv[16];
    memset( addr_str_cli, 0, 16 );
    memset( addr_str_srv, 0, 16 );
    inet_ntop( AF_INET, &(addr[0].sin_addr), addr_str_cli, 16 );
    inet_ntop( AF_INET, &(addr[1].sin_addr), addr_str_srv, 16 );
    printf( "Client: %s\nServer:%s\n", addr_str_cli, addr_str_srv );
    close( sockfd );
    return 0;
}

服务器:

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

int main( int argc, char **argv ){
    int sockfd, connfd;
    struct sockaddr_in servaddr;
    memset( &servaddr, 0, sizeof( servaddr ) );
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons( 2000 );
    servaddr.sin_addr.s_addr = htonl( INADDR_ANY );
    sockfd = socket( AF_INET, SOCK_STREAM, 0 );
    bind( sockfd, (struct sockaddr *) &servaddr, sizeof( servaddr ) );
    listen( sockfd, 5 );
    if( (connfd = accept( sockfd, (struct sockaddr *) 0, 0 )) == -1 ){
            perror( "Can't open server socket: " );
            exit( errno );
    }
    struct sockaddr_in addr[2];
    socklen_t len;
    memset( addr, 0, sizeof( struct sockaddr_in ) * 2 );
    getpeername( connfd, (struct sockaddr *) &(addr[0]), &len );
    getsockname( connfd, (struct sockaddr *) &(addr[1]), &len );
    send( connfd, addr, sizeof( struct sockaddr_in ) * 2, 0 );
    close( connfd );
    close( sockfd );
    return 0;
}

有问题的代码部分如下:

struct sockaddr_in addr[2];
socklen_t len;
memset( addr, 0, sizeof( struct sockaddr_in ) * 2 );
getpeername( connfd, (struct sockaddr *) &(addr[0]), &len );
getsockname( connfd, (struct sockaddr *) &(addr[1]), &len );
send( connfd, addr, sizeof( struct sockaddr_in ) * 2, 0 );

这是一个向客户端发送有关客户端和服务器 IP 地址的信息的服务器。当客户端和服务器 运行 在同一台机器上时,我得到服务器 IP 地址的正确值,但是当我尝试 运行 客户端和服务器在通过以太网电缆连接的两台独立计算机上时,我得到零。此外,无论我做什么,客户端的 IP 地址都为零(我不知道这是正确的还是错误的)。为什么会发生这种情况,我该如何解决?

man getpeername 明确指出(强调我的)

The address_len parameter should be initialized to indicate the amount of space pointed to by address. On return it contains the actual size of the address returned (in bytes).

The address is truncated if the buffer provided is too small.

    socklen_t len = sizeof(struct sockaddr_in);

应该可以解决问题。