目录
C/S架构
C是Client(客户端软件)
S是Server(服务端软件)
客户端基于网络发送消息给服务端的流程
客户端:
应用程序是无法直接操作硬件的
应用程序产生的数据存放于自己的内存中,
然后调用接口发送/拷贝给操作系统,
操作系统再根据应用程序指定的规则/协议,调用网卡发送数据
网络传输数据
...............................
服务端:
服务端软件调用系统接口,想要将数据从操作系统内存中拷贝到自己的内存里
服务端软件操作系统接受到这一指令后,然后按照客户端指定的协议,
从网卡接受数据,然后拷贝给服务端软件
什么是软件
笼统讲,软件就是除了硬件以外的都是软件
什么是协议
协议:在数据外包了一层,是固定长度的。在定制自己的协议的时候,报头一定是固定长度的字节
网络模型
ISO
:国际标准化组织,其定制了一个OSI
开放系统互联模型
层次是人为的划分
OSI七层 | TCP5层 | TCP4层 | 单位 | 每层的设备 | 每层的协议 |
---|---|---|---|---|---|
应用层 | 应用层 | 应用层 | HTTP、SMTP、FTP等(主要是来规定数据的格式) | ||
表示层 | |||||
会话层 | |||||
传输层 | 传输层 | 传输层 | 数据段 | 四层路由器、四层交换机 | TCP、UDP |
网络层 | 网络层 | 网络层 | 数据包 | 路由器、三层交换机 | IP、ICMP |
数据链路层 | 数据链路层 | 帧 | 网卡、交换机、网关 | Ethernet、ARP(IP->MAC)、RARP(MAC->IP) | |
物理层 | 物理层 | 物理接口层 | bit | 双绞线、集线器、中继器 |
IP地址
IP地址32位,4段点分十进制表示
IP地址的作用:
- 标识所在网络
- 标识所在网络中的哪一台主机
IPV4地址分为ABCDE类
-
A类以
0
打头
地址范围:0.0.0.0 ~ 127.255.255.255
私有地址:10.0.0.0 ~ 10.255.255.255
保留地址:127.x.x.x -
B类以
10
打头
地址范围:128.0.0.0 ~ 191.255.255.255
私有地址:172.16.0.0 ~ 172.31.255.255
保留地址:169.254.x.x -
C类以
110
打头
地址范围:192.0.0.0 ~ 223.255.255.255
私有地址:192.168.0.0 ~ 192.168.255.255 -
D类以
1110
打头
不区分网络地址和主机地址
地址范围:224.0.0.0 ~ 239.255.255.255 -
E类以
11110
打头
不区分网络地址和主机地址
地址范围:240.0.0.0 ~ 247.255.255.255
- IP地址的网络号不能全为0,但可以全为1
- IP地址的主机号不能全为0,也不能全为1
- 全为0表示本网络,全为1表示广播地址,向本网络所有主机发送消息
- 子网号可以全为0以及1
端口
端口:用来标识是哪个应用程序
端口:0 - 65535,其中 0 - 1023为系统占用
MAC地址
网络中每台设备都有一个唯一的网络标识,这个地址叫MAC地址或网卡地址,由网络设备制造商生产时写在硬件内部。
MAC
地址是48位的(6个字节),通常表示为12个16进制数,每2个16进制数之间用冒号隔开,如08:00:20:0A:8C:6D就是一个MAC地址。其前3字节表示OUI(Organizationally Unique Identifier),是IEEE的注册管理机构给不同厂家分配的代码,用来区分不同的厂家。后3个字节由厂家自行分配。
- MAC地址最高字节(MSB)的低第二位(LSb)表示这个MAC地址是全局的还是本地的,即U/L(Universal/Local)位,如果为0,表示是全局地址。所有的OUI这一位都是0。
- MAC地址最高字节(MSB)的低第一位(LSb),表示这个MAC地址是单播还是多播。0表示单播。
socket
socket
(套接字)是应用层与TCP/IP
协议簇通信的中间软件抽象层。起源于加尼福尼亚大学伯克利分校版本的Unix
,也是人们所说的BSD Unix
所以也称socket
为伯克利套接字
或者BSD套接字
。
最初被设计为同一台主机的多个应用程序之间通讯,称之为进程之间的通讯
以及IPC
。
socket
有两个种族:
- 基于文件型(AF_UNIX)
- 基于网络型的(AF_INET)默认IPV4,还有用于IPV6的(AF_INET6)
socket
是一个门面模式(一个设计模式),将复杂的TCP/IP
协议隐藏在socket
接口后面。对于用户来说就是socket
就是一个模块、一组接口。你只需调用这些接口、方法,让socket
去组织数据即可。
电信号
一组电信号称为数据报/数据帧
数据报分成两个部分:
- 报头:固定长度,18个字节
- 数据:最大1500个字节,最小46个字节
数据包
网络中传输的数据都叫做数据包
,数据包中的数据成为数据报
数据报分为:报头
和数据
两个部分
三次握手和四次挥手
通俗版
三次握手
第一次握手:客户端跟服务端说:“我可以连接你吗?”
第二次握手:服务端响应:可以啊,并且顺便询问客户端,我可以连接你吗?
第三次握手:客户端跟服务端说:“可以啊”
四次挥手
第一次挥手:客户端跟服务端说:“我要跟你断开。”
第二次挥手:服务端响应:可以啊
第三次挥手:服务端数据传输完毕后,跟客户端说:“我也要跟你断开。”
第四次挥手:客户端响应:“好的”
加分版
参考源
https://blog.csdn.net/m0_37907797/article/details/103252306
三次握手
刚开始客户端处于closed
状态,服务端处于listen
状态。
第一次握手:
客户端向服务端发送一个SYN报文,并指明客户端的初始化序列号ISN。
此时客户端处于SYN_Sent状态。
第二次握手:
服务器收到客户端的SYN报文之后,会以自己的SYN报文作为应答,
并且也指定自己的初始化序列号ISN,同时会把客户端的ISN + 1作为ACK的值,
表示自己已经收到了客户端的SYN。此时,服务器处于SYN_RCVD状态。
第三次握手:
客户端收到服务端的SYN报文,会发送一个ACK报文,
当然,也会把服务器的ISN + 1作为ACK的值,
表示已经收到了服务端的SYN报文。
此时,客户端处于established状态。
服务端收到ACK报文之后,也处于established状态,
此时,双方就建立起了连接关系。
三次握手的作用
- 确认双方的接受能力、发送能力是否正常
- 指定自已的初始化序列号,为后面的可靠传送做准备
为什么要三次握手
为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
具体例子:“已失效的连接请求报文段”的产生在这样一种情况下:
client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。
本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。
于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。
由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。
但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。
采用“三次握手”的办法可以防止上述现象发生。
例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”
为什么需要三次握手才能确认双方的接受与发送能力是否正常,而两次却不可以呢?
第一次握手:客户端发送网络数据包,服务端收到了。此时,服务端得到以下结论:客户端的发送能力以及自身的接收能力是正常的
第二次握手:服务端发送网络数据包,客户端收到了。此时,客户端得到以下结论:服务端的收发能力以及自身的收发能力都是正常的
但是,服务端并不能确认客户端的接收能力是正常的。
第三次握手:客户端发送网络数据包,服务端收到了。此时,服务端得到以下结论:客户端的收发能力以及自身的收发能力都是正常的
ISN是固定的吗?
在三次握手的过程中,最重要的一个功能就是交换ISN。
以便让对方知道接下来接收数据的时候如何按照序列号组装数据。
如果ISN是固定的,那么攻击者很容易猜出后续的确认号,因此ISN是动态生成的。
什么是半连接队列?
服务器第一次收到客户端的SYN之后,就会处于SYN_RCVD状态,
此时双方还没有完全建立其连接,服务器会将这种状态下的请求连接
放入到一个队列里,我们把这样的队列称之为半连接队列。
当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在
全连接队列中。如果队列满了就有可能会出现丢包现象。
关于SYN - ACK 重传次数问题
服务器发送完SYN - ACK包之后,如果未收到客户确认包,服务器进行首次重传,
等待一段时间后仍未收到客户端确认包,会进行第二次重传。
如果重传的次数超过系统规定的最大重传次数,
系统会将该连接信息从半连接队列中删除。
其中,每次重传的时间间隔不一定相同,一般以指数增长,
例如时间间隔为:1s,2s,4s,8s...
三次握手过程中可以携带数据吗?
在三次握手的过程中,第三次握手是可以携带数据的,前两次不能携带数据,
其中一个简单的原因就是会让服务器更容器受到攻击。
对于第三次,此时客户端已经处于established状态,
也就是说,对于客户端来说,他已经建立起了连接,并且已经知道了服务器
的收发能力是正常的了,所以携带数据是没有什么问题的。
四次挥手
刚开始双方都处于established状态,假如是客户端先发起关闭请求,则:
第一次挥手
客户端发送一个FIN报文,报文中会指定一个序列号。
此时,客户端处于closed_wait_1状态
第二次挥手
服务端收到FIN报文之后,会发送ACK报文,
且把客户端的序列号值 + 1作为ACK报文的值,
表明已经收到客户端的报文了,此时,服务端处于closed_wait_2状态。
第三次挥手
如果服务端也想断开连接了,和客户端的第一次挥手一样,
向客户端发送FIN报文,且指定一个序列号。
此时,服务端处于last_ack状态。
第四次挥手
客户端收到FIN之后,发送ACK报文作为应答,
且将服务端的序列号值 + 1作为ACK报文的序列号值。
此时,客户端处于time_wait状态。
需要过一段时间以确保服务端收到自己的ACK报文之后才会进入closed状态。
服务端收到ACK报文之后,就处于关闭连接了,也就处于closed状态。
这里特别需要主要的就是TIME_WAIT
这个状态了,就是要理解,为什么客户端发送 ACK 之后不直接关闭,而是要等一阵子才关闭。
这其中的原因就是:
要确保服务器是否已经收到了我们的 ACK 报文,
如果没有收到的话,服务器会重新发 FIN 报文给客户端,
客户端再次收到 ACK 报文之后,
就知道之前的 ACK 报文丢失了,然后再次发送 ACK 报文。
至于 TIME_WAIT 持续的时间至少是一个报文的来回时间。
一般会设置一个计时,如果过了这个计时没有再次收到 FIN 报文,
则代表对方成功就是 ACK 报文,此时处于 CLOSED 状态。
为什么要等待2MSL
2MSL,MSL:报文段最大生存时间,它是任何报文段被丢弃前在网络内的最长时间。
原因有二:
-
保证TCP协议的全双工连接能够可靠关闭
-
保证这次连接的重复数据段从网络中消失
第一点:如果主机1直接CLOSED了,那么由于IP协议的不可靠性或者是其它网络原因, 导致主机2没有收到主机1最后作为应答的ACK报文。那么主机2就会在超时之后继续发送FIN, 此时由于主机1已经CLOSED了,就找不到与重发的FIN对应的连接。 所以,主机1不是直接进入CLOSED,而是要保持TIME_WAIT, 当再次收到FIN的时候,能够保证对方收到ACK,最后正确的关闭连接。 第二点:如果主机1直接CLOSED,然后又再向主机2发起一个新连接, 我们不能保证这个新连接与刚关闭的连接的端口号是不同的。 也就是说有可能新连接和老连接的端口号是相同的。 一般来说不会出现这样的问题,但是还是有特殊情况出现: 假设新连接和已经关闭的老连接端口号是一样的, 如果前一次连接的某些数据仍然滞留在网络中, 这些延迟数据在建立新连接之后才到达主机2, 由于新连接和老连接的端口号是一样的, TCP协议就认为那个延迟的数据是属于新连接的, 这样就和真正的新连接的数据包发生混淆了。 所以TCP连接还要在TIME_WAIT状态等待2倍MSL,这样可以保证本次连接的所有数据都从网络中消失。
为什么要四次挥手?
TCP是全双工模式,这就意味着,
当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;
但是,这个时候主机1还是可以接受来自主机2的数据;
当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,
但是主机2还是可以发送数据到主机1的;
当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,
就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。
滑动窗口
所谓滑动窗口,就是在发送一个包之后,不等待ACK号的返回,直接发送后续的一系列包。有效利用等待ACK号的这段时间。
TCP与UDP的区别
TCP | UDP | |
---|---|---|
头部 | 20B | 8B |
可靠性 | 可靠 | 不可靠 |
连接性 | 面向连接 | 无连接 |
报文 | 面向字节流 | 面向报文 |
效率 | 传输效率低 | 传输效率高 |
双工性 | 全双工 | 一对一、一对多、多对一、多对多 |
流量控制 | 滑动窗口 | 无 |
拥塞控制 | 慢开始、拥塞避免、快重传、快恢复 | 无 |
系统资源 | 要求多 | 要求少 |
传输速度 | 慢 | 快 |
应用场景 | 对效率要求低,对准确性要求高或者要求有连接的场景 | 对效率要求高,对准确性要求低 |