(三)TCP三次握手和连接队列——网络编程

1)预备知识:

1.1)计算机网络体系结构

        原理体系网络中:

        1)物理层:解决使用何种信号来传输比特的问题。

        2)数据链路层:解决分组在一个网络(或者一端链路)上传输的问题。

        3)网络层:解决分组在多个网络上传输(路由)的问题。

        4)运输层:解决进程之间基于网络的通信问题 。

        5)应用层:解决通过应用进程的交互来实现特定网络应用的问题。

 1.2)运输层

        计算机网络体系结构中的物理层、数据链路层、网络层共同实现了主机到主机的通信,但实际上在计算机网络中进行通信的真正实体是位于通信两端主机中的进程。运输层直接为应用进程间的逻辑通信提供服务。

        运输层向高层用户屏蔽了下面网络核心的细节,它使应用进程看见的就好像是在两个运输层实体之间有一条端到端的逻辑通信信道。

        根据应用需求的不同,因特网的运输层提供了两种不同的运输协议,即面向连接的TCP和无连接的UDP。

  1.3)TPC/UDP      

        UDP(User Datagram Protocol)用户数据报协议,支持单播、多播以及广播,向上层提供无连接不可靠传输服务,适用于IP电话、视频会议等实时应用。

        TCP(Transmission Control Protocol)传输控制协议,仅支持单播,向上层提供面向连接的可靠传输服务,适用于要求可靠传输的应用,例如文件传输。

        TCP/IP体系的应用层常用协议所使用的运输层熟知端口号。

         

2)TCP三次握手

2.1)简单流程:

        1)客户端发送带有SYN标志的连接请求数据报给服务器。

        2)服务端发送带有SYN+ACK标志的连接请求和应答数据报给客户。

        3)客户端发送带有ACK标志的应答数据报给服务端(可以携带数据)

2.2)详细流程:

        1)服务进程监听某个端口,处于 listen 状态。

        2)客户进程向服务进程发送TCP连接请求报文段,并进入同步已发送状态。TCP连接请求报文段首部中的同步位SYN=1,表明这是一个TCP连接请求报文段;序号字段seq随机设置一个初始值x,作为初始序列号(client_isn);TCP规定SYN=1的报文段不能携带数据,但是要消耗一个序号。

        3)服务进程收到TCP连接请求报文段后,如果同意建立连接,则向TCP客户进程发送TCP连接请求确认报文段,进入同步已接受状态。设置SYN=1,ACK=1表明这是一个SYN握手和ACK确认应答报文;随机一个初始序列号(server_isn)seq=y;ack=x+1是对客户端发送的TCP连接请求报文段的确认seq=x的确认。

        4)客户进程收到TCP连接请求确认报文段后,向TCP服务进程发送一个普通的TCP确认报文段,并进入连接已建立状态。ACK=1表示这是一个应答报文;ack=y+1是对服务器发送的seq=y报文的确认。TCP连接请求报文段初始序号为seq=x,消耗一个序号,故本报文seq=x+1。此次报文可以携带数据,如果不携带数据则不消耗序号。

        5)服务进程收到该确认报文段后也进入连接已建立状态。

2.3)为什么是三次握手:

        主要原因:防止历史连接

        在网络堵塞的情况下,客户进程第一次握手的SYN报文迟迟没有达到服务进程,客户进程没有收到服务进程SYN+AKC报文,触发超时重传,那么有可能出现后发送的SYN报文比早发送的SYN报文早到达了服务端,此时服务进程都会发送一个SYN+ACK报文给客户进程:

        1)如果是两报文连接,就不能判断当前连接是否是历史连接,导致错误,浪费资源。如果服务进程后接收到了早发送SYN报文,服务进程发送SYN+ACK报文后会直接进入连接已建立状态,此时客户进程可能已经完成上次TCP连接,处于关闭状态,且两报文也不会发送ACK确认报文,使得服务进程一直在连接已建立状态,等待客户进程发送数据,从而浪费资源。

        2)如果是三报文连接,客户进程如果还在开启状态,可根据自身上下文,判断这是一个历史连接(序列号或超时),给服务进程发送RST报文,终止这一次连接。如果客户进程关闭,服务进程长时间没有收到ACK报文,会释放掉该连接。

 3)连接队列

        内核会为listen状态的socket维护两个队列:不完全连接请求队列(SYN_RECV状态)和等待accept建立socket的队列(ESTABLISHED状态)。

        listen()函数声明如下:

int listen(int socket, int backlog);

        第二个参数backlog指等待accept的完全建立socket(ESTABLISHED状态)的队列的长度。

        不完全连接请求队列的长度在如下文件中设置(缺省值为128):

/proc/sys/net/ipv4/tcp_max_syn_backlog

4)补充

4.1)SYN攻击

        SYN攻击属于DoS(Denial of Service 拒绝服务)攻击的一种,通过大量发送伪造源IP的第一次握手SYN包,占满不完全连接请求队列,导致正常的连接请求无法成功。

        解决方法:

        1)限制IP连接次数

        2)增大不完全连接状态的队列容量:增大内存资源占用,不推荐

        3)延迟分配连接资源。传统都是在不完全连接队列是就为每个连接分配相应的资源,可以延迟资源分配在完全连接队列中。SYN发送大量SYN请求,只要服务器不分配相应资源,就不至于遭到严重破坏。

4.2)初始序列号为什么随机产生

        保证网络通信安全,否则黑客可以很容易获得你与其他主机间通信的初始序列号,从而伪造序列号进行攻击。

4.3)为什么SYN不携带数据却要消耗一个序号

        因为SYN段需要对方确认,只有占用一个序列号才能确保这个确认不会出现歧义。

4.4)每次握手的意义

        第一次握手:client无信息,server确认对方发送正常,自己接受正常。

        第二次握手:client确认自己发送、接受正常,对方发送、接受正常。

        第三次握手:server确认自己发送正常,对方接受正常。

4.5)TCP连接过程中,客户端中途宕机,客户端恢复后,向服务端发送SYN包重新建立连接,此时服务端会怎么处理

        TCP连接主要由客户端IP、服务端IP、端口号确定。

        1)端口不相同。此时服务端会任务是新的连接要建立,于是通过三次握手来建立新的连接。旧连接会出发TCP保活机制,检测到客户端没有存活后,服务端会释放掉旧的连接。

        2)端口相同。TCP发送SYN包,服务端回复一个携带了上次报文的确认号和序列号,这个ACK称为Challenge ACK,客户端收到Challenge ACK,发现序列号并不是自己期望收到的,于是就会发送RST报文,服务端收到后,就会释放掉该连接。

猜你喜欢

转载自blog.csdn.net/weixin_43284996/article/details/128127264