我的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端口。
答案 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中,它将此类连接称为同时连接。