POSIX套接字客户端连接到自身

时间:2017-06-23 17:11:07

标签: c++ sockets client centos7 vmware-workstation

我的TCP客户端套接字代码的行为非常奇怪,所以我编写了一个简单的测试程序。

以下代码旨在不断重试连接到服务器(127.0.0.1:36000),直到连接为止。正在使用g++ 4.8.5编译-std=c++98(不能使用C ++ 03/11)。

#include <arpa/inet.h>
#include <cctype>
#include <cerrno>
#include <cstring>
#include <iostream>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>

int main()
{
    int sd = -1;

    while (true)
    {
        close(sd);

        std::cout << "trying to connect" << std::endl;

        if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        {
            std::cerr << strerror(errno) << std::endl;
            continue;
        }

        std::cout << "socket created " << sd << std::endl;

        struct sockaddr_in addr;
        memset((char *)&addr, 0, sizeof(struct sockaddr_in));
        addr.sin_family = AF_INET;

        if (!inet_aton("127.0.0.1", &addr.sin_addr))
        {
            std::cerr << strerror(errno) << std::endl;
            continue;
        }
        std::cout << "translated ip" << std::endl;

        addr.sin_port = htons(36000);

        if (connect(sd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
        {
            std::cerr << "Error connecting socket" << std::endl;
            continue;
        }

        std::cout << "connected " << inet_ntoa(addr.sin_addr) << ":" << ntohs(addr.sin_port) << std::endl;
        std::cout << "write " << write(sd, "from client", 11) << std::endl;

        char buf[1024] = {0};
        int size;
        while ((size = read(sd, buf, 1024, 0, NULL, NULL)) > -1)
        {
            buf[size] = 0;
            std::cout << "received " << size << " ["  << buf << "]" << std::endl;
        }

        std::cout << "stopped" << std::endl;
    }

    return 0;
}

尽管没有使用端口36000的服务器或任何其他程序,但connect调用成功,write也是如此。我得到的输出看起来像:

trying to connect
socket created 3
translated ip
Error connecting socket
trying to connect
socket created 3
translated ip
Error connecting socket
...
...
...
trying to connect
socket created 3
translated ip
connected 127.0.0.1:36000
write 11
received 11 [from client]

如果端口更改为任何其他未使用的端口(35999,36001等),connect将仅失败(连接被拒绝)。其他端口似乎永远不会连接。

如果参数recvfrom存在,则不会修改它们。

此外,它仅在套接字未超时时发生。如果套接字仍然超时,connect将失败。

netstat -an被阻止时运行read将返回

tcp        0      0 127.0.0.1:36000         127.0.0.1:36000         ESTABLISHED

这发生在CentOS 6.7和7个vms上。

发生了什么事?端口36000有什么奇怪的吗?这是Centos / connect错误吗?我在做些傻事吗?

这是How can you have a TCP connection back to the same port?的部分副本,但仍然无法解释为什么它只发生在36000端口。

1 个答案:

答案 0 :(得分:2)

当我使用tcpdump运行执行程序时,我得到了一些有趣的输出。

sudo tcpdump -i lo

...
14:51:16.477170 IP localhost.35988 > localhost.36000: Flags [S], seq 3826079620, win 65495, options [mss 65495,sackOK,TS val 95720198 ecr 0,nop,wscale 7], length 0
14:51:16.477173 IP localhost.36000 > localhost.35988: Flags [R.], seq 0, ack 3826079621, win 0, length 0
14:51:16.477203 IP localhost.35990 > localhost.36000: Flags [S], seq 2431563950, win 65495, options [mss 65495,sackOK,TS val 95720198 ecr 0,nop,wscale 7], length 0
14:51:16.477206 IP localhost.36000 > localhost.35990: Flags [R.], seq 0, ack 2431563951, win 0, length 0
14:51:16.477247 IP localhost.35992 > localhost.36000: Flags [S], seq 3688613148, win 65495, options [mss 65495,sackOK,TS val 95720198 ecr 0,nop,wscale 7], length 0
14:51:16.477250 IP localhost.36000 > localhost.35992: Flags [R.], seq 0, ack 3688613149, win 0, length 0
14:51:16.477282 IP localhost.35994 > localhost.36000: Flags [S], seq 1503921089, win 65495, options [mss 65495,sackOK,TS val 95720198 ecr 0,nop,wscale 7], length 0
14:51:16.477285 IP localhost.36000 > localhost.35994: Flags [R.], seq 0, ack 1503921090, win 0, length 0
14:51:16.477315 IP localhost.35996 > localhost.36000: Flags [S], seq 2868111150, win 65495, options [mss 65495,sackOK,TS val 95720198 ecr 0,nop,wscale 7], length 0
14:51:16.477318 IP localhost.36000 > localhost.35996: Flags [R.], seq 0, ack 2868111151, win 0, length 0
14:51:16.477348 IP localhost.35998 > localhost.36000: Flags [S], seq 281293569, win 65495, options [mss 65495,sackOK,TS val 95720198 ecr 0,nop,wscale 7], length 0
14:51:16.477351 IP localhost.36000 > localhost.35998: Flags [R.], seq 0, ack 281293570, win 0, length 0
14:51:16.477381 IP localhost.36000 > localhost.36000: Flags [S], seq 3196081163, win 65495, options [mss 65495,sackOK,TS val 95720198 ecr 0,nop,wscale 7], length 0
14:51:16.477386 IP localhost.36000 > localhost.36000: Flags [S.], seq 3196081163, ack 3196081164, win 65495, options [mss 65495,sackOK,TS val 95720198 ecr 95720198,nop,wscale 7], length 0
14:51:16.477422 IP localhost.36000 > localhost.36000: Flags [.], ack 1, win 512, options [nop,nop,TS val 95720198 ecr 95720198], length 0

此输出显示套接字实际上正在与自身执行TCP 3次握手。出于某种原因(至少在CentOS 6.7中)它似乎是将源端口递增2,从而防止端口35999,36001上出现问题。

RFC 793中,它将此类连接称为同时连接。