首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >套接字连接到不存在的ip地址上的端口。

套接字连接到不存在的ip地址上的端口。
EN

Stack Overflow用户
提问于 2016-04-12 22:13:39
回答 2查看 71关注 0票数 0

下面的代码用于套接字连接到运行在Ubuntu15.10上的服务器:

代码语言:javascript
复制
    void Connect(std::string address, int port)
    {
            struct addrinfo hints;
            struct addrinfo *result = NULL;
            struct addrinfo *rp = NULL;
            int sfd, s;

            std::cout << "Connecting to address " << address << " port " << port << std::endl;

            std::memset(&hints, 0, sizeof(struct addrinfo));

            hints.ai_family = AF_UNSPEC;        /* Allow IPV4 or IPV6 */
            hints.ai_socktype = SOCK_DGRAM;     /* Datagram socket */
            hints.ai_flags = 0;
            hints.ai_protocol = 0;              /* Any protocol */

            std::string portStr;
            portStr = std::to_string(port);

            s = getaddrinfo(address.c_str(), portStr.c_str(), &hints, &result);

std::cout << "ADDRESS-------------> " << s << std::endl;
            if (s != 0)
            {
                std::stringstream ss;
                ss << "Cannot resolve hostname " << address << gai_strerror(s);
                throw std::runtime_error(ss.str());
            }

            /*
             *  getaddrinfo() returns a list of address structures. We should try each
             *  address until we successfull bind. If socket() or connect() fails, we close the socket
             *  and try the next address until the end.
             */
            for (rp = result; rp != NULL; rp = rp->ai_next)
            {
    std::cout << "loop-----------------> " << rp->ai_family << std::endl;
                sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
    std::cout << "sfd-----------------> " << sfd << std::endl;

                if (sfd == -1)
                    continue;

    /*
                 *  If connect succeed, the address was found.
                 */
                int sts = connect(sfd, rp->ai_addr, rp->ai_addrlen);

    std::cout << "sts-----------------> " << sts << std::endl;

                if (sts == 0)
                    break;

                close(sfd);
            }

            /*
             *  Check for failure
             */
            if (rp == NULL)
            {
                std::stringstream ss;
                ss << "Cannot find server address at " << address << " port " << port;
                throw std::runtime_error(ss.str());
            }

            freeaddrinfo(result); /* Object no longer needed */

    std::cout << "SOCKET-----------------> " << sfd << std::endl;

            currentSocket = sfd;

    }

我的问题是,这段代码正在连接套接字,即使IP地址不可用。检查结果:

以下是运行时输出:

代码语言:javascript
复制
    Connecting to address 192.168.0.185 port 9090
    ADDRESS-------------> 0
    loop-----------------> 2
    sfd-----------------> 5
    sts-----------------> 0
    SOCKET-----------------> 5

$ ping 192.168.0.185
PING 192.168.0.185 (192.168.0.185) 56(84) bytes of data.
From 192.168.0.185 icmp_seq=1 Destination Host Unreachable
From 192.168.0.185 icmp_seq=2 Destination Host Unreachable
From 192.168.0.185 icmp_seq=3 Destination Host Unreachable

我想了解这是怎么回事?为什么它将套接字从一个不存在的Ip地址连接到一个端口?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-04-12 22:26:11

您正在将一个IPv4地址而不是主机名传递给getaddrinfo() (不过,您应该在hints.ai_flags字段中指定AI_NUMERICHOST )。它将输出一个包含该IP地址的sockaddr_in的单个sockaddr_in,因为它不会试图验证IP的存在。这就是为什么getaddrinfo()返回0。

您告诉getaddrinfo(),您将使用的是UDP (SOCK_DGRAM)套接字,而不是TCP (SOCK_STREAM)套接字。因此,输出addrinfo包含在调用socket()时创建UDP套接字的信息。

然后在UDP套接字上调用connect()。在UDP中,connect()实际上并不像对TCP那样创建物理连接。它只是将指定的对等IP分配给套接字,这样就可以使用send()recv()来代替sendto()recvfrom()。这就是为什么connect()返回0而不是失败的原因。这样做允许send()始终将数据包发送到同一个IP,而recv()只接收来自同一个IP的数据包。

您还没有实际发送任何数据,因此在代码的任何一步都不会验证对等IP。一旦开始发送数据,传输的数据包最终将从网络接收ICMP主机无法访问的错误,从而导致send()recv()开始失败。

因此,如果希望connect()对不可访问的IP地址失败,请创建一个TCP套接字而不是UDP套接字。否则,如果您继续使用UDP套接字,则需要将数据发送到IP,以便网络将其物理路由。

顺便说一下,如果connect()确实失败了,那么只有在freeaddrinfo()成功的情况下,您才会泄漏输出addrinfo,因为您正在调用freeaddrinfo()。无论您如何使用freeaddrinfo()数据,只要getaddrinfo()成功,您都需要调用addrinfo

票数 3
EN

Stack Overflow用户

发布于 2016-04-12 22:37:07

UDP 'connect‘不是网络操作。它在本地API中设置了一个允许,它过滤掉来自其他主机的数据报,并允许您使用send()而不是sendto()。它不会失败,但随后会发送遗嘱。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36584995

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档