关于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;
}

服务端:

#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;
}

其中的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;
}

时间: 2024-10-14 15:17:18

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

UNIX网络编程——getsockname和getpeername函数

UNIX网络编程——getsockname和getpeername函数 来源:网络转载   http://www.educity.cn/linux/1241293.html 这两个函数或者返回与某个套接字关联的本地协议地址(getsockname),或者返回与某个套接字关联的外地协议地址即得到对方的地址(getpeername). #include <sys/socket.h> int getsockname(int sockfd,struct sockaddr* localaddr,sock

getsockname函数与getpeername函数的使用

getsockname和getpeername函数 getsockname函数用于获取与某个套接字关联的本地协议地址 getpeername函数用于获取与某个套接字关联的外地协议地址 定义如下: #include<sys/socket.h> int getsockname(int sockfd, struct sockaddr *localaddr, socklen_t *addrlen); int getpeername(int sockfd, struct sockaddr *peerad

(转载)你好,C++(27)在一个函数内部调用它自己本身 5.1.5 函数的递归调用

你好,C++(27)在一个函数内部调用它自己本身 5.1.5 函数的递归调用 5.1.5 函数的递归调用 在函数调用中,通常我们都是在一个函数中调用另外一个函数,以此来完成其中的某部分功能.例如,我们在main()主函数中调用PowerSum()函数来计算两个数的平方和,而在PowerSum()函数中,又调用Power()函数和Add()函数来计算每个数的平方并将两个平方加和起来成为最终的结果.除此之外,在C++中还存在另外一种特殊的函数调用方式,那就是在一个函数内部调用它自己本身,这种方式也被

你好,C++(27)在一个函数内部调用它自己本身 5.1.5 函数的递归调用

5.1.5 函数的递归调用 在函数调用中,通常我们都是在一个函数中调用另外一个函数,以此来完成其中的某部分功能.例如,我们在main()主函数中调用PowerSum()函数来计算两个数的平方和,而在PowerSum()函数中,又调用Power()函数和Add()函数来计算每个数的平方并将两个平方加和起来成为最终的结果.除此之外,在C++中还存在另外一种特殊的函数调用方式,那就是在一个函数内部调用它自己本身,这种方式也被称为函数的递归调用. 函数的递归调用,实际上是实现函数的一种特殊方式.当递归函

Bash脚本之函数定义和调用

把那些在脚本中重复出现并且没有任何改变的代码,封装起来,在适当的场景中调用执行.程序员将这种被封装起来的代码称为功能体,或者叫模块,也称为函数.这样看来是不是和循环类似,循环也是为了方便去多次执行一堆代码,而函数是将一堆代码写在一起,起一个名字,然后在需要这堆代码的时候只需要写上函数的名字即可.在shell脚本编程中,函数是由若干条shell命令组成的语句块,函数里面的内容和shell程序形式上是一致的.不同之处就是,shell代码可以直接被执行,而函数中的内容,不能独立执行,只有被调用的时候才

实验八——函数定义及调用总结

实验八--函数定义及调用总结 1.本次课学习到的知识点: (1)void为不反回结果的函数,且void不能省略,否则默认为int,函数体中没有表达式的return语句,也可省略return. (2)不返回结果的函数在定义.调用.参数传递.函数声明上,思路与以前相同,适用于把一些确定的.相对独立的程序功能封装成函数. (3)局部变量:定义在函数的内部,且有效作用范局部变量一般定义在函数或复合语句的开始处,围局限于所在的函数内部,形参是局部变量. (4)不能定义在中间位置. (5)全局变量:定义在函

php闭包实现函数的自调用,也是递归

php的闭包可能不常用,但是在某些场合之下还是可以考虑用php的闭包来实现某些功能的,比如递归,这里讲一下用php的闭包实现递归 //php闭包实现函数的自调用,也就是实现递归 function closure($n,$counter,$max){ //匿名函数,这里函数的参数加&符号是,引址调用参数自己 $fn = function (&$n,&$counter,&$max=1) use(&$fn){//use参数传递的是函数闭包函数自身 $n++; if($n

用函数实现登陆功能(三次机会),然后在主函数中根据调用后的结果判断 登陆成功与否。

/*3.用函数实现登陆功能(三次机会),然后在主函数中根据调用后的结果判断登陆成功与否.*/#include <string.h>int numb(char use[] ,char password[] ){ if((strcmp(use,"zhouyi")==0)&&(strcmp(password,"nb")==0)) { return 1; } else { return 0; } } #include <stdio.h>

C++面试题1:构造函数和虚构函数中能否调用虚函数?

C++面试题1:构造函数和虚构函数中能否调用虚函数? 构造函数跟虚构函数里面都可以调用虚函数,编译器不会报错. C++ primer中说到最好别用 由于类的构造次序是由基类到派生类,所以在构造函数中调用虚函数,虚函数是不会呈现出多态的 类的析构是从派生类到基类,当调用继承层次中某一层次的类的析构函数时意味着其派生类部分已经析构掉,所以也不会呈现多态 因此如果在基类中声明的纯虚函数并且在基类的析构函数中调用之,编译器会发生错误. class Base { public: Base() { Fuct