首页 > 代码库 > 关于getsockname()/getpeername()函数第一次被调用得到0.0.0.0结果的说明

关于getsockname()/getpeername()函数第一次被调用得到0.0.0.0结果的说明

最近阅读UNIX网络编程第四章时,书本末尾介绍了两个函数getsockname()和getpeername(),可以用于获取服务器端和客户端的IP地址与端口,原本很简单的两个函数,过一眼即明白函数的用法,但在实际编程测试中,却出现了一个让人意外的结果,这两个函数在第一个客户连接时解析出的IP地址和端口全部为0,出乎我的期望。而在后面的客户连接时,打印出的IP地址和端口却是正确的。

下面先给出客户端和服务端的代码:

客户端:

技术分享
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <pton32>
#include <iostream>


int main(int argc, char const *argv[])
{
    int         sockfd;
    sockaddr_in srvaddr;

    bzero(&srvaddr, sizeof(srvaddr));
    srvaddr.sin_family = AF_INET;
    if (argc < 2)
    {
        std::cout << "usage:" << argv[0] << " <IP address>" << std::endl;
        return -1;
    }
    srvaddr.sin_addr = pton32(argv[1]);
    srvaddr.sin_port = htons(7777);

    sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (connect(sockfd, (sockaddr *)&srvaddr, sizeof(srvaddr)) != 0)
    {
        std::cout << "connect error,retry please.";
        throw;
    }

    char str[128] = {\0};
    while ((read(sockfd, str, 127)) > 0)
    {
        std::cout << str <<  ;
    }

    std::cout << std::endl;

    close(sockfd);

    return 0;
}
View Code

 

服务端:

技术分享
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <pton32>
#include <iostream>


int main(int argc, char const *argv[])
{
    int             listenfd, connfd;
    sockaddr_in     cliaddr, srvaddr;

    bzero(&srvaddr, sizeof(srvaddr));
    srvaddr.sin_family              = AF_INET;
    srvaddr.sin_addr.s_addr         = htonl(INADDR_ANY);
    srvaddr.sin_port                = htons(7777);

    listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (bind(listenfd, (sockaddr *)&srvaddr, sizeof(srvaddr)))
    {
        std::cout << "bind failed." << std::endl;
        return -1;
    }

    if (listen(listenfd, 32))
    {
        std::cout << "listen failed." << std::endl;
        return -1;
    }

    char str[128] = {\0};

    bzero(&cliaddr, sizeof(cliaddr));

    while (true)
    {
        socklen_t length        = sizeof(cliaddr);
        connfd = accept(listenfd, (sockaddr *)&cliaddr, &length);

        sockaddr_in     local,          peer;
        socklen_t       local_len,      peer_len;
        bzero(&local, sizeof(local));
        bzero(&peer, sizeof(srvaddr));

        getsockname(connfd, (sockaddr *)&local, &local_len);
        getpeername(connfd, (sockaddr *)&peer,  &peer_len);

        char buff_local[64] = {\0}, buff_peer[64]  = {\0};

        if (inet_ntop(AF_INET, (void *)&local.sin_addr, buff_local, 63))
        {
            std::cout << buff_local << std::endl;
        }

        if (inet_ntop(AF_INET, (void *)&peer.sin_addr, buff_peer, 63))
        {
            std::cout << buff_peer << std::endl;
        }

        write(connfd, str, 127);
        close(connfd);
    }
    return 0;
}
View Code

 

其中的pton32头文件是我个人自定义的头文件,用于转换IP地址,定义如下:

技术分享
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <iostream>


in_addr pton32(const char *str)
{
        in_addr s_addr;
        try
        {
                if (1 == inet_pton(AF_INET, str, &s_addr))
                        return s_addr;
                else
                        throw false;
        }
        catch (bool b)
        {
                std::cout << "convert failed." << std::endl;
        }

        bzero(&s_addr, sizeof(s_addr));
        return s_addr;
}
View Code

 

 

关于getsockname()/getpeername()函数第一次被调用得到0.0.0.0结果的说明