结合代码一文弄清TCP三次握手,四次挥手,TIME_WAIT、CLOSE_WAIT状态

最近做了一个项目,其中有个模块用了C/S架构,SOCKET产生了很多TIME_WAIT。虽然知道TIME_WAIT本身是不可避免的,但借此机会结合代码全面理清TCP的连接机制也好。示例代码中Client端是用C写的,Server端是用Go写的。

TCP连接

如下图这是一张完整的TCP链接交互过程,包含建立时的三步握手,建立后的数据发送,以及关闭时的四步握手

TCP的链接是从三步握手开始的,第一个SYN报文是由Cient端发起的, Client端发起请求前Server端必须已经处于Listen状态,如下如图:

[root@sndbassitapp03 ~]# netstat -an |grep 8888
tcp        0      0 :::8888                     :::*                        LISTEN 

Server端的代码:

	ln, err := net.Listen("tcp", ":8887")
	if err != nil {
		panic(err)
        return
	}

	defer ln.Close()
	mlog.log.Informational("This is a TCP Server 8887 !!!!")
	for {
		conn, err := ln.Accept()
		if err != nil {
			panic(err)
		}
        //业务处理代码
		time.Sleep(time.Second * 1)
	}

 这时候Client还没有发起请求,所以在Client系统中没有该TCP流信息

[wjm@localhost ~]$ netstat -an |grep 8888
[wjm@localhost ~]$ 

Client端的代码:

if((_sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    return -1;
}
if (connect(_sockfd, (struct sockaddr *)&_serveraddr, sizeof(struct sockaddr)) < 0)             
{
    close(_sockfd);
    _sockfd = -1;
    return -1;
}

Client运行后,向Server端发起请求,过程如下图: 

链接建立后,TCP流状态就会变成ESTABLSHED:

Clinet端:

[root@localhost pagent]# netstat -an |grep 8887
tcp        0      0 127.0.0.1:34149             127.0.0.1:8887              ESTABLISHED 

Server端: 

tcp        0      0 :::8887                     :::*                        LISTEN      
tcp        0      0 ::ffff:127.0.0.1:8887       ::ffff:127.0.0.1:34149      ESTABLISHED 

到此Client和Server就能分别调用send和receive函数接收,发送给数据了。

 

关闭连接

 

Client端和Server端都可以主动发起close,tcp close的四步握手流程如下图:

T

从上图看到的主动发起close的一方最后肯定是要进入TIME_WAIT状态的,如下图

[root@localhost pagent]# netstat -an |grep 8887
tcp        1      0 127.0.0.1:34149             127.0.0.1:8887              TIME_WAIT  

 TIME_WAIT存在的目的是为了等待对端完全关闭。如上图主动close的一方在收到对端发送的Fin Ack后,返回Ack并进入到TIME_WAIT状态。如果对端没有收到这个ACK报文,那它还会继续发送Fin Ack报文,如果没有TIME_WAIT状态,就会返回RST对对端,显然对端希望收到的是ACK,而不是RST。

TIME_WAIT持续2MSL(一个MSL是30秒),不可以修改该时间,但是Linux提供了其它的优化手段,通过proc接口提供了一些优化手段:

1.tcp_max_tw_buckets

通过设置该值控制time_wait的数量

[root@localhost ipv4]# cat /proc/sys/net/ipv4/tcp_max_tw_buckets
131072

2. tcp_tw_reuse

允许将time_wait 的流重新用于新的TCP连接

3.tcp_tw_recycle

快速回收time_wait

总结

主动close的一方不可避免的会进入到TIME_WAIT状态,优化手段治标不治本,在设计的时候应该如何规避TIME_WAIT呢

1.尽量不要在服务端主动CLOSE

2.降低创建CLOSE的次数

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值