在分布式服务化架构设计中,服务与服务之间通信均是基于网络底层协议来实现的,于是我们需要对网络相关基础知识有一个基本的认知,这样在我们服务与服务之间进行通信(跨进程通信)过程能够在我们的脑图形成一个基本的数据传输流程以及其中的细节问题,这样对于我们在进行网络问题的排查能够带来一定的帮助.现在开始展开网络基础相关知识的阐述.
网络基础
协议是计算机与计算机之间通过网络通信时事先达成的一种“约定”,这种“约定”使那些由不同的厂商设备,不同的CPU以及不同的操作系统组成的计算机之间,只要遵循相同的协议就能够在网络传输中实现数据交互的通信.
分组交换
在网络传输过程中,如果传输的数据块很大,则需要将其切成多个以包为单位的数据块进行传输,而这种将数据分装为一个个以包为单元的数据块称为分组.
网络数据包
数据包(报文)由控制信息(称为报文首部抑或是header)以及用户数据(也称为有效负载payload),控制信息包含有效负载的传输信息,即数据包的源IP地址/目标IP地址/分组之后的序号以便于在接收端的目标IP机器能够根据序号进行拼接组成一个与源数据包一致的数据块.
一个完整的数据包组成的结构如下:
分组交换协议
为了保证发送端与接收端能够正确进行通信,分组的两端必须保持报文首部和内容保持一致的约定,即房租交换协议.
协议栈(网络堆栈)
一组可以协同工作的网络协议层,定义七个协议层的OSI参考模型通常称为栈,定义Internet上的TCP/IP协议集也称为栈.术语的堆栈s指处理协议的实际软件.
IP堆栈的含义
一般最普遍的网络堆栈的实现为一个互联网的协议栈,也称为IP栈,在操作系统中,IP栈提供了一套应用程序库,用于与远程设备建立和关闭链接以及在远程设备之间发送和接收数据,而这其中的一套应用程序库就是我们熟知的Socket API库,并且几乎所有提供IP堆栈的平台上的api都是一致的.TCP/IP栈提供了socket套接字用于接收和发送来自应用程序的请求,而应用程序具备选择TCP/UDP(UDP也有所属于自己的一套应用程序库来接收和发送数据)不同的协议来进行数据传输.于是在IP堆栈中提供UDP以及TCP两种协议并为两种协议提供相应的应用程序库,当我们应用程序选择TCP协议来进行网络通信的时候,此时就会将一套支持TCP协议的socket库加载到IP栈中,并将TCP协议绑定到我们的INC接口来实现与远程设备的数据传输.
协议栈与OSI七层参考模型
TCP/IP四层模型
通过上图可知,我们可以很清晰地看出OSI与TCP/IP分层模型之间的联系与区分,同时每一层都对应到我们的计算机中的应用程序,操作系统和网卡硬件设备接口.
TCP/IP协议
三次握手
进行三次握手的原因
半连接与全连接队列
SYN攻击(DDos攻击)
SYN攻击就是客户端在短时间内伪造大量不存在的IP地址,并向服务端不断地发送SYN报文请求,由于源IP地址不存在,于是服务为了回复确认请求的报文SYN并等待客户端的响应ACK,导致服务端需要不断重发直至超时,而这些伪造的SYN报文将长时间占用在未连接队列中,这样容易使得正常的SYN报文请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪.SYN 攻击是一种典型的 DoS/DDoS 攻击.
一般通过以下命令进行排查:
netstat -n -p TCP | grep SYN_RECV
预防SYN攻击手段:
四次挥手过程
进行四次挥手的原因
主要是服务端在接收到客户端发送连接请求的报文FIN的时候,此时服务端并不能立即关闭,因为此时可能存在未处理完的网络通信,需要等待网络通信处理完成才能向客户端发送连接关闭确认报文,但是为了避免客户端不知道情况,于是就发送一个请求响应的报文段(ACK=1,seq=v,ack=u+1)告知客户端,“你的关闭连接请求报文我收到了,但是我这边连接关闭还需要等待一段时间才能关闭,晚点我再给你发一个报文确认请求”.
为什么TCP网络传输需要引入滑动窗口
通过上述图示对比可知:
滑动窗口与流量控制
为了防止服务端(或者称为接收端)接收到一个毫无关系的数据包并在当前的数据包进行耗时的处理而导致正常的数据包因处于高负载的情况被丢弃而重发消耗网络流量,于是就有了流量控制.
为了避免TCP一开始发送较大量的数据包而导致网络拥堵瘫痪的问题,在通信一开始时就会通过一个叫做慢启动的算法得出数值,对发送数据量的控制.
一般情况下出现粘包以及拆包现象主要是在网络传输的过程自定义协议,但是对于自定义的协议进行解析的时候存在一些换行.空格等一些特殊字符,这些特殊字符需要我们在应用层上进行手动处理来保证是一个完整的数据消息片段.
// 代码表现
// 客户端发送数据
String m1 = "this is the first msg";
String m2 = "this is the second msg";
client.send(m1);
client.send(m2);
// 服务端接收数据
while(true){
String msg = server.read();
log.info("msg=" + msg);
}
// msg.log
// msg = this is the first msgthis is the second msg
// 代码表现
// 客户端发送数据
String m1 = "this is the first msg";
String m2 = "this is the second msg";
client.send(m1);
client.send(m2);
// 服务端接收数据
while(true){
String msg = server.read();
log.info("msg=" + msg);
}
// msg.log
// msg = this is the first msgthis is
// msg = the second msg
一般需要我们进行自定义的协议,大部分都是编写框架或者是公司内部的一些基础的通用技术支持,在Java网络编程中一般底层网络利用Netty框架来帮助我们快速实现一个高性能的web服务,而Netty框架本身提供了编解码器来帮助我们解决上述的粘包与拆包问题.
后续关于Netty的编解码器再重新写一篇文章来阐述,在这里仅需知道什么是粘包与拆包即可.
HTTP/HTTPS协议
最后,关于上述的描述,摘录《图解HTTP》截图说明,
http 方法明细如下:
http 的持久连接明细如下:
http 管线化(pipeline)如下:
curl -v https://www.baidu.com
GET / HTTP/1.1 ### 请求行(请求方法 + http协议版本)
Host: www.baidu.com
User-Agent: curl/7.54.0
Accept: */*
curl -i https://www.baidu.com
HTTP/1.1 200 OK ### 状态行(http协议版本 + 状态码)
Accept-Ranges: bytes
Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
Connection: keep-alive
Content-Length: 2443
Content-Type: text/html
Date: Thu, 21 May 2020 06:57:08 GMT
Etag: "58860402-98b"
Last-Modified: Mon, 23 Jan 2017 13:24:18 GMT
Pragma: no-cache
Server: bfe/1.0.8.18
Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
<!DOCTYPE html>
<!--STATUS OK--><html> .... </html>
## Cache-Control: 控制缓存行为
## Pragma: 报文指令
## Transfer-Encoding: 指定报文主体的传输编码方式
## Via: 代理服务器信息
## Warning: 错误通知
## Accept: 通知服务器用户代理可处理的媒体类型以及媒体类型的相对优先级
## Accept-Charset: 用户代理可处理的字符集,用q表示优先级
## Accept-Encoding: 用户代理可以处理的内容编码,如gzip等
## Authorization: 用户代理需要进行认证授权信息
## Referer: 告知服务器请求资源的原始uri
## Location: 响应状态码返回302的时候会携带Location的uri
## WWW-Authorization: 当客户端发起请求的授权认证不对的时候服务端会返回401并携带此响应信息指定认证方式
## Allow: 允许使用的http方法
## Content-Length: 实体主体部分的大小
## Content-Range: 数据太大,分组发送,告知当前数据发送的字节大小资源情况
## 缓存控制,Cache-Control 与 Pragma
## Cache-Control: no-store 没有缓存
## Cache-Control: no-cache 缓存但重新验证,有缓存但未过期,响应返回304
## Cache-Control: private | public 缓存默认私有/公有(中间代理、CDN等代理中间件缓存)
## Cache-Control: max-age=31536000 | must-revalidate 缓存过期与验证
## Pragma,与Cache-Control: no-cache定义一致,但是定义Pragma以向后兼容基于HTTP/1.0的客户端,不能拿来完全替代HTTP/1.1中定义的Cache-control头
## 缓存失效时间计算公式: expirationTime = responseTime + freshnessLifetime - currentAge
## 可以查看头部信息的Cache-Control: max-age=N | expires | Last-Modified
## 缓存验证
## ETags:作为缓存的一种强校验器,ETag响应头是一个对用户代理(User Agent,即UA)不透明,如果资源请求的响应头里含有ETag,客户端可以在后续的请求的头中带上If-None-Match头来验证缓存
## Last-Modified 响应头可以作为一种弱校验器。说它弱是因为它只能精确到一秒。如果响应头里含有这个信息,客户端可以在后续的请求中带上 If-Modified-Since 来验证缓存
## 当向服务端发起缓存校验的请求时,服务端会返回 200 ok表示返回正常的结果或者 304 Not Modified(不返回body)表示浏览器可以使用本地缓存文件。304的响应头也可以同时更新缓存文档的过期时间
## Vary响应
## Vary: User-Agent,缓存服务器需要通过UA判断是否使用缓存的页面.如果需要区分移动端和桌面端的展示内容,利用这种方式就能避免在不同的终端展示错误的布局
## X-FRAME-OPTIONS: 在html使用iframe标签的时候,是否允许跨域访问,有DENY/SAMEORIGN/ALL
## X-XSS-Protection: 针对跨站脚本攻击的防护机制开关,0 - XSS过滤设置无效, 1 - 设置为有效
https协议是在http的基础上增加一层SSL/TLS协议,也就是HTTP部分接口使用SSL/TLS协议来代替进行密文加密传输数据.
https采用非对称的公开密钥加密和对称加密的共享加密并用的混合加密机制,同时为了保证公开的密钥是可信任的,于是需要第三方的认证机构颁发证书来完成公开密钥的认证.具体的https加密执行流程如下:
最后感谢花时间阅读,如果有收获欢迎动一动小手指转发或者好看,谢谢!