TCP连接与断开

transmission control protocol  传输控制协议

基于字节流的通信协议

数据在传输前要建立连接,传输完毕要断开连接

客户端在收发数据前要使用connnect函数和服务器建立连接

建立连接的目的是保证ip地址、端口等正确无误,为数据的传输开辟通道

tcp建立连接时腰传输三个数据包,俗称三次握手

1)当客户端调用connect函数后,tcp协议会组建一个数据包,并设置syn标志位

表示数据包是用来建立同步连接的,同时生成一个随机数字1000,

填充 序号seq字段,表示该数据包的序号,完成这些工作

开始向服务器发送数据包,客户端就进入syn-send状态

2)服务器端收到数据包,检测到已经设置了syn标志位,就知道客户端

发来的建立连接的请求包,服务器端也会组建一个数据包

并设置syn和ack标志位,syn表示该数据包是用来建立连接的

ack用来确认收到了刚才客户端发来的数据包

服务器生成一个随机数2000,填充序列号seq

2000 和客户端数据包没有关系

服务器将客户端数据包序列号加1,并用这个数据自填充a

确认号ack字段

服务器将数据包发出,进入syn-recv状态

 

3)客户端收到数据包,检测到已经设置了syn和ack标志位

就知道这就是服务器发来的  确认包。

客户端会检测确认号ack字段,看他的值是否为1000+1,

如果是就说明连接建立成功

客户端将数据包发出,进入establelised状态,表示连接已经建立成功

 

4)服务器收到数据包,检测已经设置了ack标志位,就知道是客户端发来的、

确认包,服务器会检测确认号ack字段,看他的值是否是2000—+1

如果是表明建立连接成功,服务器进入estableised状态

 

说明:三次握手的关键是要确认对方收到自己的数据包

就是通过确认号ack实现的,计算机会记录下自己

发送的数据包序列号seq,待接收到对方的数据包后,检测

确认号ack = seq + 1是否成立,如果成立说明对方正确接收到了自己的数据包

 

二:tcp数据的传输过程

    

ack号的增量=传输数据的字节数,假设每次ack

号不加传输的字节数,这样虽然可以确认数据包的传输,

但是无法明确100字节全部传输正确还是丢失了一部分

ack = seq + 传递字节数 + 1;

最后加一是为了告诉对方要传递的seq号

 

上图表示通过数据包想主机b发送100字节的数据

单中间发生了错误,主机b未收到。经过一段时间后,主机A

仍未收到ack确认,因此尝试重传数据。

为了完成数据包的重传,Tcp套接字每次发送数据包时都会启动定时器

如果在一定时间内没有收到目标机器的回传ack包

那么定时器超时,数据包会重传。

重传超时时间( rto, retransmission time out)

这个值他打了会导致不必要的等待时间,太小了会导致不必要的重传

 

RTT( round trip time ):往返延时,在计算机网络中他是一个重要的性能指标

表示从发送端发送数据开始,到发送端收到来自接收端的确认,总共经历的延时

 

 

重传次数

tcp包的重传次数根据系统设置的不同而不同,有些重传三次,又得要求

很高的系统,会不断重传丢失的数据包

三:tcp四次握手断开连接

建立连接非常重要,他是数据正确传输的前提

断开连接同样重要,他让计算机释放不再使用的资源

如果连接不能正常断开,不仅会造成数据传输错误

还会导致套接字不能关闭,持续占用资源,如果并发量高

服务器压力堪忧

 

建立连接后,客户端和服务器都处于establised状态

这时,客户端发起断开连接的请求

1)客户端调用close()函数后,向服务器发送fin数据包,进入fin_wait_1状态

fin是finish的缩写,表示完成任务需要断开连接

2)服务器接收到数据包后,检测到设置了fin标志位,

知道要断开连接,于是想客户端发送  确认包 ,进入cclose_wait状态

注意:服务器接收到请求后,并不是立即断开连接,而是先向客户端发哦送确认包

告诉他我知道了,我需要准备一下,才能断开连接

3)客户端收到确认包 后,进入fin_wait_2状态,等待服务器准备完毕再次发送数据包

4)等待片刻后,服务器准备完毕,可以断开连接,于是再主动

向客户端发送fin包, 告诉他我准备好了,断开连接吧,

然后进入last_ack状态

5)客户端接收到服务器的fin包后,再向服务器发送ack包

告诉他你断开连接吧,然后进入time_wait状态

6)服务器接收到客户端的ack包后,就断开连接,关闭套接字,进入closed状态

关于time_wait状态的说明

客户端最后一次发送ack包后进入time_wait状态,而不是直接

进入closed状态,这是为什么呢

tcp是面向连接的传输方式,必须保证数据能够正确到达目标机器,不能

丢失或出错,而网络是不稳定的,随时可能会毁坏数据,所以

机器A每次向B发送数据包后,都要求机器B确认,回传ack包

告诉机器A才能知道数据传送成功了,如果机器B没有回传

机器A会重新发送,知道机器B回传ack包

客户端最后一次向服务器回传ack时,有可能会因为网络问题导致服务器收不到

服务器会再次发送fin包,如果这是客户端完全管理了连接,那么服务器无论如何也收不到ack包了,

所以客户端需要等待片刻,确认对方收到ack包后,才能进入closed状态

那么,要等多久呢?

数据包在网络中是有生存时间的,超过这个时间还未到达目标主机

就会被丢弃,并通知源主机。这称为报文最大生存时间

time_wait要等待2个报文最大生存时间,ACK包到达服务器需要最大报文生存时间

服务器重传也需要msl时间,如果2msl后还未收到服务器重传的ifn包,

就说明服务器已经收到ack包

四:优雅的断开连接--shutdown()

      调用close() /closesocket函数意味着完全断开连接,既不能发送数据也不能接收数据

这种生硬的方式

 

上图演示了两台正在进行双向通信的主机

主机A发送完数据后,单方面调用close()、closesocket断开连接

之后主机A , B 都不能再接受对方传输的数据

实际上,是完全无法调用与数据收发有关的函数

一般情况下这不会有问题,单有些特殊时刻,需要只断开一条数据传输通道

而保留另一条。

使用shutdown函数可以达到这个目的

int shutdown( int sock, int howto ) //linux

int shutdown( SOCKET s, int howto ) //windows

sock为需要断开的套接字,howto为断开方式

SHUT_RD:断开输入流

SHUT_WR:断开输出流

close() /closesocket() /shutdown的区别

确切额说,close()、closesocket用来关闭套接字,将套接字描述符从内存

中清除,之后再也不能使用该套接字,

shutdown用来关闭连接,而不是套接字,不管调用多少次,

套接字依然存在,知道调用close

默认情况下,close()/close()会立即向网络中发送FIN包,

不管输出缓冲区中是否还有数据,而shutdown会等输出缓冲区的数据传输完毕再发送

FIN包,也就意味着,调用close将丢失缓冲区中的数据,

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值