TCP和UDP是传输层的协议,目的都是在程序之间传输数据
TCP不能保证数据对方一定能接收到,它不是100%可靠的协议,所以能提供的是数据的可靠传递或故障的可靠通知。
首先TCP是一个以太网协议栈,主要实现的是消息收发,一般是应用层进行数据传输,这时调用操作系统进行消息传递,操作系统就交由协议栈来处理。
可能会认为有IP协议来进行分发即可,为什么还需要TCP来中间处理,这是因为IP协议只是一个地址协议,并不保证数据包的完整,如果路由器丢包(比如缓存满了,新进来的数据包丢失),就需要发现丢了哪一个包,以及如何重新发送这个包
简单说,TCP协议的作用是保证数据通信的完整性和可靠性,防止丢包
以太网数据包的大小是固定的,如今为1522字节
,其中1500字节
是负载,22字节
是头信息
而IP数据包也有自己的头信息,最少需要20字节,即负载最多为1480字节,而TCP数据包也需要存储头信息,因此其最大负载是1480 - 20 = 1460字节,除此之外还有额外的头信息,所以实际TCP负载为1400字节左右,因此一条1500字节的信息需要两个TCP数据包
由于有时需要发送多个包,即拆开了后那么客户端需要想办法让服务端知道怎么样算收到所有的包,且应该以怎么样的顺序组装,而且某个包未收到也能通知客户端进行重传,所以设置了seq
位,即序号位
服务端收到了一个TCP包,查看他的seq为1,而负载为1000,则服务端马上就知道下一个要收到的应该是1001的seq的包,而且可以根据这个顺序来组装这些包
当然实际情况下,TCP的第一个包的seq不会是1,而是随机计算的一个数,这是为了不被人轻易猜出传输的顺序等,所以服务端想知道哪个是第一个包,这时就要介绍一个连接的过程了
客户端想和服务端建立连接,就是所谓的三次握手
,客户端先从应用程序的套接字拿到ip和端口,之后向服务端发送第一个包即SYN段,将包头中SYN
设置为1,且也将计算的初始序列号(Sequence number)在这里一起传输给服务端,
这样就可以解决上面说的问题,这是第一次握手的过程
第二次握手
自然就是服务端的返回,服务端会返回SYN+ACK段,即在包头中SYN和ACK位
字段设置为1的数据包,且由于TCP通讯是全双工的,即服务端也能向客户端发送消息,所以需要将服务端的初始序列号也发给客户端,这一步也是在这里一起发的,而最后一步就是设置Acknowledgement number = J+1来表示确认已收到客户端的SYN段的(Sequence number = J)
那接下来就来到第三次握手
了,客户端会给服务端一个ACK段响应(包头中ACK位字段设置为1),该段中使Acknowledgement number = K + 1表示收到服务器的SYN段(Sequenct number = K)
第一次握手
客户端经过socket()创建套接字,进行connect()后主动(active open)连接上服务器,发送SYN,这时客户端的状态是SYN_SENT
,服务端则进行socket(),bind(),listen()后等待客户的连接,收到连接后服务端将该连接的状态会变为SYN_RCVD
状态,然后将连接信息放到半连接队列(Syn queue)中,如果半连接队列已满,则服务器不会修改该连接的状态为SYN_RCVD
,且将该连接直接丢弃
syn flood 攻击就是利用队列已满则丢弃连接的原理进行攻击,应对方法之一就是使得syncookies生效,设置为1,这样即使队列满了也可以接受正常的非恶意攻击的客户端请求
攻击方的客户端只发送SYN给服务器,然后对服务端的返回不进行处理,直接忽略掉,而不是发送ACK给服务端,这样这个连接就会一直占据着服务器的半连接队列的资源,导致正常的客户端连接无法连接上服务器
(SYN flood攻击方式分为两种,第一种是攻击方客户端一直发送SYN,对于服务器响应直接忽略,第二种是发送SYN时,将源IP改为一个虚假的IP,然后服务器将SYN+ACK发送到虚假的IP,这样也得不到ACK响应)
第二次握手
服务器返回SYN+ACK后,客户端收到该段,则状态从SYN_SENT变为ESTABLISHED,即既定状态
第三次握手
这时服务端收到客户端发送的ACK,则该连接状态从SYN_RCVD变为ESTABLISHED,然后服务器将该连接从半连接队列中移除,连接信息放到全连接队列中,如果全连接队列已满,则不会修改连接状态
为什么要三次握手而不是两次握手?
防止已失效的连接请求又传送到服务端,因而产生错误
或者看看第三次握手,主要也是对接受发的起始序列号进行确认,如果没有第三次握手则另外一分的序列号不能被确认
首要原因是防止旧的重复连接初始化造成混乱
有这样一个场景,客户端发送了SYN报文(seq=90),然后客户端宕机了,而且这个SYN报文被网络堵塞了,服务端没有收到,接着客户端重启后,再次向服务端建立连接,发送SYN(seq=100)报文,而如果旧的比新的先到达了,那么第三次握手就会传递一个RST报文告诉服务端,这个连接过期了,不要用了。
断开连接 - 四次挥手
本文作者:Malyue
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!