zoukankan      html  css  js  c++  java
  • 利用 getsockname 和 getpeername 来获取某一个链接的本地地址和远端地址

    在两台计算机上建立一个网络连接,需要五个要素:本机地址 本机端口 协议类型 远端端口 远端地址.那么如何从一个建立好的连接上获取这些信息呢.就需要用到

     getsockname  和 getpeername 这两个函数.

    但前提是要在建立好的连接上.

    作为客户端,要在正确调用connect()之后,才能使用这两个函数

    作为服务端,要在正确调用accept()之后,才能使用这两个函数

    以下为测试代码, windows/linux 下均可编译运行.

    #include <stdint.h>
    #include <stdio.h>
    #include <memory.h>
    
    #ifdef WIN32
    #include <windows.h>
    typedef int32_t socklen_t;
    #define close(x) closesocket(x)
    #else
    #include <errno.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #define INVALID_SOCKET (-1)
    typedef int32_t SOCKET;
    #endif
    
    int32_t Errno()
    {
    #ifdef WIN32
        return WSAGetLastError();
    #else
        return errno;
    #endif
    }
    
    void test_getname(SOCKET sock, const char *desc)
    {
        printf("%s
    ", desc);
        struct sockaddr_in addr;
        socklen_t addr_len = sizeof(addr);
        int32_t ret = getsockname(sock, (struct sockaddr *)&addr, &addr_len);
        if(ret == 0)
        {
            printf("getsockname succ:%s:%d
    ", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
        }
        else
        {
            printf("getsockname failed,error=%d
    ", Errno());
        }
    
        memset(&addr, 0, sizeof(addr));
        ret = getpeername(sock, (struct sockaddr *)&addr, &addr_len);
        if(ret == 0)
        {
            printf("getpeername succ:%s:%d
    ", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
        }
        else
        {
            printf("getpeername failed,error=%d
    ", Errno());
        }
    }
    
    void test_connect()
    {
        sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = inet_addr("127.0.0.1");
        addr.sin_port = htons(5000);
    
        SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        test_getname(sock, "before connect");
    
        int32_t ret = connect(sock, (sockaddr*)&addr, sizeof(addr));
        if(ret != 0)
        {
            printf("connect error, errno: %d
    ", Errno());
            return;
        }
        test_getname(sock, "after connect");
        close(sock);
    }
    
    void test_accept()
    {
        SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(INVALID_SOCKET == sock)
        {
            printf("create socket error,errno=%d
    ", Errno());
            return;
        }
    
        sockaddr_in srvAddr;
        memset(&srvAddr, 0, sizeof(srvAddr));
        srvAddr.sin_family = AF_INET;
        srvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
        srvAddr.sin_port = htons(5000);
    
        test_getname(sock, "before bind");
        int32_t ret = bind(sock, (sockaddr*)&srvAddr, sizeof(srvAddr));
        printf("bind:%s:%d
    ", inet_ntoa(srvAddr.sin_addr), ntohs(srvAddr.sin_port));
        test_getname(sock, "after bind");
        if(ret != 0)
        {
            printf("bind listen socket error,errno=%d
    ", Errno());
            return;
        }
        ret = listen(sock, SOMAXCONN);
        if(ret != 0)
        {
            return;
        }
        sockaddr_in cliAddr;
        socklen_t cliAddrLen = sizeof(cliAddr);
        SOCKET new_sock = accept(sock, (sockaddr*)&cliAddr, &cliAddrLen);
        printf("accept:%s:%d
    ", inet_ntoa(cliAddr.sin_addr), ntohs(cliAddr.sin_port));
        test_getname(new_sock, "after accept");
        close(sock);
        close(new_sock);
    }
    
    int32_t main()
    {
    #ifdef WIN32
        WSADATA wsaData;
        WSAStartup(MAKEWORD(2, 2), &wsaData);
    #endif
        //test_connect();
        test_accept();
    #ifdef WIN32
        WSACleanup();
    #endif
        getchar();
        return 0;
    }

    测试结果:

    connect:

    before connect
    getsockname failed,error=10022
    getpeername failed,error=10057
    after connect
    getsockname succ:127.0.0.1:4618
    getpeername succ:127.0.0.1:5000

    accept:

    before bind
    getsockname failed,error=10022
    getpeername failed,error=10057
    bind:0.0.0.0:5000
    after bind
    getsockname succ:0.0.0.0:5000
    getpeername failed,error=10057
    accept:127.0.0.1:4630
    after accept
    getsockname succ:127.0.0.1:5000
    getpeername succ:127.0.0.1:4630
  • 相关阅读:
    搭建elk的坑
    mail发邮件报错 "send-mail: fatal: parameter inet_interfaces: no local interface found for ::1"
    shell脚本排坑
    rocketmq双主发送消息 SLAVE_NOT_AVAILABLE 状态
    基于mysql的基准测试
    mysql服务器参数
    MySql Host is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts' 解决方法
    mysql存储引擎
    zabbix安装
    iostat查看系统的IO负载情况
  • 原文地址:https://www.cnblogs.com/tangxin-blog/p/7348558.html
Copyright © 2011-2022 走看看