本节来重现TCP可能出现异常的原因中部分为三次握手的出现的问题.
服务端没有监听
服务端没有监听, 客户端发送ACK而服务端TCP协议返回一个RST段, 客服端调用connect
返回错误, 错误类型是ECONNREFUSED.
这个实验随便之前的哪一个代码都可以, 只运行客户端的程序, 抓包就可以看到 :
SYN后没收到ACK确认报文
客户端一直没有收到对端的ACK
确认报文, 当超时后继续发送FIN, 多次失败之后客户端停止尝试连接并且客户端connect
函数返回错误, 错误类型是ETIMEOUT.
ECONNABORTED
三次握手成功了, 但是客户端立马发送一个RST
段后断开而服务端处于繁忙状态, 等服务端返回时才发现对端已经关闭, 此时服务端也关闭. 客户端connect
后立即断开, 服务端在accept
函数返回前收到RST
段, 则accept
函数返回ECONNABORTED(该错误errno依赖操作系统).
完整代码 accept_ECONNABORTED.c.
这里罗列的代码 :
服务端在listen之后, accept之前睡眠5秒.
// 服务端
int service(int port, const char *ser_addr)
{
int sockfd, clientfd;
sockfd = Socket(0);
Bind(sockfd, port, ser_addr);
listen(sockfd, 1);
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
sleep(5);
return 0;
}
客户端调用setsockopt
函数, 设置SO_LINGER, 客户端在 close 的时候不是发送 FIN, 而是RST.
// 客户端
int client(int port, const char *cli_addr)
{
int sockfd;
sockfd = Socket(0);
Connect(sockfd, port, cli_addr);
// 设置套接字选项
struct linger lig;
lig.l_onoff = 1;
lig.l_linger = 0;
// 客户端在 close 的时候不是发送 FIN,而是 RST.
if(setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (void *)&lig, sizeof(lig)) != 0)
EXIT("setsockopt");
return 0;
}
运行时客户端后马上中断连接, 可以抓包看到, 客户端发送的不是FIN.
总结
还有很多错误的可能性没有整理, 但也不好实验, 所以三次握手的问题就暂时这些吧.