文章参考来源:
为运行在不同主机上的应用进程提供直接的通信服务,向上层屏蔽下面的网络核心细节如(网络拓扑、路由器选择协议等),使应用进程仿佛是存在一条端到端的逻辑通信信道。根据应用需求的不同,向应用层提供两种不同的运输协议即面向连接的TCP协议和无连接的UDP协议
(Process ID)运行在计算机机上的进程使用进程标识符PID标志(不同操作系统使用不同格式的进程标识符)
(Port ID)为了使运行不同操作系统的计算机应用进程之间能够进行网络通信而使用统一的方法对应用进程进行标识,端口号具有本地意义,因特网中不同计算机中的相同端口号是没有联系的。端口号用16比特表示,取值范围0~65535
windows系统中怎么查看PID与端口号?
1、Windows下查看PID与端口号:使用快捷键Ctrl+Shift+Esc呼出任务管理器后点击服务可查看 或者 使用快捷键win+r后再输入cmd回车,使用
tasklist
命令查看2、Linux下使用命令
netstat -tunlp
查看或者ps
多个用户使用一个IO资源 发送消息 时,我们称之为“复用”。
多个用户使用一个IO资源 接收消息 时,我们称之为 “分用” 。
在网络层
局域网内多个主机利用一个路由网关发送消息给互联网的其他主机。这也是复用技术。
同理,利用网关接收路由数据报就叫 分用技术。
在运输层
操作系统的 多个进程(这里一个端口表示一个进程) 利用一个运输层协议(或者称为运输层接口)发送数据称为复用
同理,接收时叫做 分用。
在应用层
操作系统的 多个线程 利用一个端口(或者叫socket,socket = IP+端口号 )发送消息称为“”复用“”(有一个技术名词“”IO多路复用“”讲着的大概就是这个意思)
同理,接收时叫分用
💦 用户数据报协议 UDP(User Datagram Protocol):
💦 传输控制协议 TCP(Transmission Control Protocol):
三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的 初始化序列号(Init Sequense Number, ISN
) 为后面的可靠性传输做准备。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kH63)(Typora\typora-user-images\image-20220114221054079.png)]
SYN
:连接请求/接收 报文段seq
:发送的第一个字节的序号ACK
:确认报文段ack
:确认号。希望收到的下一个数据的第一个字节的序号1)第一次握手:客户端向服务端发送一个 SYN 报文(SYN = 1),并指明客户端的初始化序列号 ISN(x),即图中的 seq = x,表示本报文段所发送的数据的第一个字节的序号。此时客户端处于 SYN_Send
状态。
2)第二次握手:服务器收到客户端的 SYN 报文之后,会发送 SYN 报文作为应答(SYN = 1),并且指定自己的初始化序列号 ISN(y),即图中的 seq = y。同时会把客户端的 ISN + 1 作为确认号 ack 的值,表示已经收到了客户端发来的的 SYN 报文,希望收到的下一个数据的第一个字节的序号是 x + 1,此时服务器处于 SYN_REVD
的状态。
3)第三次握手:客户端收到服务器端响应的 SYN 报文之后,会发送一个 ACK 报文,也是一样把服务器的 ISN + 1 作为 ack 的值,表示已经收到了服务端发来的的 SYN 报文,希望收到的下一个数据的第一个字节的序号是 y + 1,并指明此时客户端的序列号 seq = x + 1(初始为 seq = x,所以第二个报文段要 +1),此时客户端处于 Establised
状态。
第三次握手是否多余?
不多余!这是为了防止已失效的连接请求报文段延时到达TCP服务器导致错误比如资源浪费,同时使服务器端确认了:自己发送正常、对方接收正常。
为什么TCP的标准规定SYN=1的报文段不能携带数据?
但是消耗掉一个序列号,而普通的报文段如果不携带数据则不消耗序列号
假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据,然后疯狂重复发 SYN 报文的话(因为攻击者根本就不用管服务器的接收、发送能力是否正常,它就是要攻击你),这会让服务器花费很多时间、内存空间来接收这些报文。
而对于第三次的话,此时客户端已经处于 ESTABLISHED
状态。对于客户端来说,他已经建立起连接了,并且也已经知道服务器的接收、发送能力是正常的了,所以当然能正常发送/携带数据了。
所以,第三次握手可以携带数据的。但是,第一次、第二次握手绝对不可以携带数据。
ISN (Initial Sequence Number) 是固定的吗
三次握手的其中一个重要功能是客户端和服务端交换 ISN(Initial Sequence Number),以便让对方知道接下来接收数据的时候如何按序列号组装数据。
当一端为建立连接而发送它的 SYN 时,它会为连接选择一个初始序号。ISN 随时间而变化,因此每个连接都将具有不同的 ISN。如果 ISN 是固定的,攻击者很容易猜出后续的确认号,因此 ISN 是动态生成的。
连接队列
服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD
状态,此时双方还没有完全建立其连接,服务器会把这种状态下的请求连接放在一个队列里,我们把这种队列称之为半连接队列。
当然还有一个全连接队列,完成三次握手后建立起的连接就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。
SYN 洪泛攻击
SYN 攻击就是 Client 在短时间内伪造大量不存在的 IP 地址,并向 Server 不断地发送 SYN 包,Server 则回复确认包,并等待 Client 确认,由于源地址不存在,因此 Server 需要不断重发直至超时,这些伪造的 SYN 包将长时间占用半连接队列,导致正常的 SYN 请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。
如果第三次握手丢失了,客户端服务端会如何处理
服务器发送完 SYN-ACK 包,如果未收到客户端响应的确认包,也即第三次握手丢失。那么服务器就会进行首次重传,若等待一段时间仍未收到客户确认包,就进行第二次重传。如果重传次数超过系统规定的最大重传次数,则系统将该连接信息从半连接队列中删除。
Server 端
第三次的ACK在网络中丢失,那么Server 端该TCP连接的状态为SYN_RECV,并且会根据 TCP的超时重传机制,会等待3秒、6秒、12秒后重新发送SYN+ACK包,以便Client重新发送ACK包。
而Server重发SYN+ACK包的次数,可以通过设置/proc/sys/net/ipv4/tcp_synack_retries修改,默认值为5.
如果重发指定次数之后,仍然未收到 client 的ACK应答,那么一段时间后,Server自动关闭这个连接。
Client 端
在linux c 中,client 一般是通过 connect() 函数来连接服务器的,而connect()是在 TCP的三次握手的第二次握手完成后就成功返回值。也就是说 client 在接收到 SYN+ACK包,它的TCP连接状态就为 established (已连接),表示该连接已经建立。那么如果 第三次握手中的ACK包丢失的情况下,Client 向 server端发送数据,Server端将以 RST包响应,方能感知到Server的错误。
建立一个 TCP 连接需要三次握手,而终止一个 TCP 连接要经过四次挥手(也有将四次挥手叫做四次握手的)。这是由于 TCP 的半关闭(half-close)特性造成的,TCP 提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。
TCP 连接的释放需要发送四个包(执行四个步骤),因此称为四次挥手(Four-way handshake
),客户端或服务端均可主动发起挥手动作。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zu364)(Typora\typora-user-images\image-20220114221355677.png)]
FIN
:连接终止位seq
:发送的第一个字节的序号ACK
:确认报文段ack
:确认号。希望收到的下一个数据的第一个字节的序号刚开始双方都处于ESTABLISHED
状态,假设是客户端先发起关闭请求。四次挥手的过程如下:
1)第一次挥手:客户端发送一个 FIN 报文(请求连接终止:FIN = 1),报文中会指定一个序列号 seq = u。并停止再发送数据,主动关闭 TCP 连接。此时客户端处于 FIN_WAIT1
状态,等待服务端的确认。
FIN-WAIT-1
- 等待远程TCP的连接中断请求,或先前的连接中断请求的确认;
2)第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序号值 +1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT
状态。
CLOSE-WAIT
- 等待从本地用户发来的连接中断请求;
此时的 TCP 处于半关闭状态,客户端到服务端的连接释放。客户端收到服务端的确认后,进入FIN_WAIT2
(终止等待 2)状态,等待服务端发出的连接释放报文段。
FIN-WAIT-2
- 从远程TCP等待连接中断请求;
3)第三次挥手:如果服务端也想断开连接了(没有要向客户端发出的数据),和客户端的第一次挥手一样,发送 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK
的状态,等待客户端的确认。
LAST-ACK
- 等待原来发向远程TCP的连接中断请求的确认;
4)第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答(ack = w+1),且把服务端的序列值 +1 作为自己 ACK 报文的序号值(seq=u+1),此时客户端处于 TIME_WAIT
(时间等待)状态。
TIME-WAIT
- 等待足够的时间以确保远程TCP接收到连接中断请求的确认;
🚨 注意 !!!这个时候由服务端到客户端的 TCP 连接并未释放掉,需要经过时间等待计时器设置的时间 2MSL(一个报文的来回时间) 后才会进入 CLOSED
状态(这样做的目的是确保服务端收到自己的 ACK 报文。如果服务端在规定时间内没有收到客户端发来的 ACK 报文的话,服务端会重新发送 FIN 报文给客户端,客户端再次收到 FIN 报文之后,就知道之前的 ACK 报文丢失了,然后再次发送 ACK 报文给服务端)。服务端收到 ACK 报文之后,就关闭连接了,处于 CLOSED
状态。
为什么要四次挥手?
由于 TCP 的半关闭(half-close)特性,TCP 提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。
任何一方都可以在数据传送结束后发出连接释放的通知,待对方确认后进入半关闭状态。当另一方也没有数据再发送的时候,则发出连接释放通知,对方确认后就完全关闭了TCP连接。
通俗的来说,两次握手就可以释放一端到另一端的 TCP 连接,完全释放连接一共需要四次握手。
举个例子:A 和 B 打电话,通话即将结束后,A 说 “我没啥要说的了”,B 回答 “我知道了”,于是 A 向 B 的连接释放了。但是 B 可能还会有要说的话,于是 B 可能又巴拉巴拉说了一通,最后 B 说“我说完了”,A 回答“知道了”,于是 B 向 A 的连接释放了,这样整个通话就结束了。
首部固定部分各字段意义如下:
1 - 源端口和目的端口:各占 2 个字节,分别写入源端口和目的端口。IP 地址 + 端口号就可以确定一个进程地址
2 - 序号/序列号(Sequense Number,SN):在一个 TCP 连接中传送的字节流中的每一个字节都按顺序编号。该字段表示本报文段所发送的数据的第一个字节的序号。初始序号称为 Init Sequense Number, ISN
例如,一报文段的序号是 101,共有 100 字节的数据。这就表明:本报文段的数据的第一个字节的序号是 101,最后一个字节的序号是 200。显然,下一个报文段的数据序号应当从 201 开始,即下一个报文段的序号字段值应为 201。
3 - 确认号 ack:期望收到对方下一个报文段的第一个数据字节的序号。若确认号为 N,则表明:到序号 N-1 为止的所有数据都已正确收到。
4 - 数据偏移(首部长度):它指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远。这个字段实际上是指出TCP报文段的首部长度。
5 - 保留:占 6 位,应置为 0,保留为今后使用。
⭐ 大家看上图,保留位的右边还有 6 个控制位(重要),这是TCP 用来说明该报文段性质的:
紧急位 URG:当 URG = 1 时,表明此报文段中有紧急数据,是高优先级的数据,应尽快发送,不用在缓存中排队。该控制位需配合紧急指针使用(紧急指针指出本报文段中紧急数据的字节数)
举个例子:我们需要取消一个已经发送了很长程序的运行,因此用户从键盘发出中断命令。如果不使用紧急数据,那么这个指令将存储在接收 TCP 的缓存末尾,只有在所有的数据被处理完毕后这两个字符才被交付接收方的应用进程,这样做就无法实现立即中断。
确认 ACK:仅当 ACK = 1 时确认号字段才有效,当 ACK = 0 时确认号无效。TCP 规定,在连接建立后所有传送的报文段都必须把 ACK 置为 1。
推送 PSH:当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应。在这种情况下,TCP 就可以使用推送(push)操作。这时,发送方 TCP 把 PSH 置为 1,并立即创建一个报文段发送出去。接收方 TCP 收到 PSH = 1 的报文段,就尽快地交付接收应用进程。而不用等到整个缓存都填满了后再向上交付。
复位 RST:当 RST = 1 时,表明 TCP 连接中出现了严重错误(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立传输连接。
同步 SYN:SYN = 1 表示这是一个连接请求或连接接受报文。
当 SYN = 1 而 ACK = 0 时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使 SYN = 1 且 ACK = 1。
终止 FIN:用来释放一个连接。当 FIN = 1时,表明此报文段的发送发的数据已发送完毕,并要求释放运输连接。