目录

TCP-IP协议栈

连接

连接是一个逻辑概念,物理层面就是一个对象(Socket)代表着若干资源

多线程复用一个连接

https://gitee.com/lienhui68/picStore/raw/master/null/20200828234720.png

需要保证并发的安全性,互斥地使用连接。

一个线程一个连接

https://gitee.com/lienhui68/picStore/raw/master/null/20200828234807.png

连接数会很多

注意多线程复用连接和连接池复用连接是两个维度的概念。

多线程复用连接是多个线程互斥地使用连接,连接池复用连接是客户端使用完连接后并不销毁,而是将连接放回连接池,以供下一个请求访问使用。

演示

服务端:

1
$  nc -l localhost 8081

客户端:

1
$ nc localhost 8081
1
2
nc只接受一个连接,一对一的方式,再有连接请求进来不接受accept,可以使用程序的方式进行连接
两个终端不能同时使用nc连接服务端

查看资源占用情况:

1
$ netstat -natp

https://gitee.com/lienhui68/picStore/raw/master/null/20200829202611.png

TCP/IP 协议栈

https://gitee.com/lienhui68/picStore/raw/master/null/20200829002948.png

  • 软件工程学中分层的目的是为了解耦
  • https看似tcp/ip协议,实际上有点osi参考模型的影子,是否加密在表示层,token、证书的验证在会话层。
  • 每一层都有各自的协议指导工作以及库函数辅助工作
  • rpc自定义协议是在应用层自定义协议,比如嫌弃http协议低效自定义应用层协议,这一层协议是由程序员赋能出来的。
  • 应用层以下是内核帮我们实现好的,对程序员透明。

应用层

模拟应用层通信

首先使用nc与服务器建立连接,这一步相当于应用层以下已经建立好连接,后面要做的就是在应用层与服务器根据应用层协议进行通信。

1
$ nc www.baidu.com 80

https://gitee.com/lienhui68/picStore/raw/master/null/20200829003927.png

1
$ netstat -natp

https://gitee.com/lienhui68/picStore/raw/master/null/20200829004018.png

基于HTTP协议通信

1
GET / HTTP/1.0 换行符

回车

https://gitee.com/lienhui68/picStore/raw/master/null/20200829004712.png

响应头 两个换行符 响应体(BODY)

再比如连接redis服务器

https://gitee.com/lienhui68/picStore/raw/master/null/20200829024419.png

如上就是按照redis-cli和redis-server之间的协议进行交互。

TCP层

https://gitee.com/lienhui68/picStore/raw/master/null/20200829195204.png

通过三次数据包的交互,开辟资源socket代表对方

https://gitee.com/lienhui68/picStore/raw/master/null/20200829195650.png

连接 三次握手 四次挥手

为什么是三次的, 连接是双向的,服务端发送ack之后需要客户端给到一个确认

连接走通之后需要开辟资源 开辟内存空间接受队列 发送队列,用socket表示,连接是逻辑概念,资源是物理概念。

可靠的传输协议:确认机制,传输控制层发送确认,如果没确认则重传,一定次数后就算失败。

三次握手进行连接,确认机制保证了可靠的传输。

释放端口号 释放内存空间

socket 代表了应用层访问tcp层的sap(服务访问点),四元组(唯一性,ip:port + ip:port 唯一确认,区分每个socket对应关系)

之前jdk使用socket对象代表socket,通过socket对象获取独立的输入输出流。jdk7有了nio,使用channel表示socket,channel可读可写,再也不用获得独立的输入输出流了。跟linux中的文件描述符保持一致(0 1 2)。

ip:为了找到主机

port:为了找到运行在主机上的进程,进程映射

  1. 连接一台服务器的某个进程,客户端消耗多少个端口号 65535
  2. 连接一台服务器的某个进程,服务端消耗多少个端口号 1
  3. 连接两台服务器,消耗多少个端口号 2 * 65535
  4. 第一个问题,如何突破65535, 客户端增加一个网卡

https://gitee.com/lienhui68/picStore/raw/master/null/20200829201542.png

jmeter就可以通过这种方式在单机情况下造成更多连接

端口号

服务端 确定的端口号,比如80

客户端 随机端口号 最多65535个

为什么断开连接需要四次挥手?

三次握手,建立了资源,断开连接就是释放资源

客户端发送FIN后, 接受队列得保留着,服务端发送FIN+ACK只是表示接受到了FIN信号,但是可能还会继续发送数据包

当服务端也发送FIN后表示不再继续发送数据包,客户端发送ACK,再等待一定时间后(TIME_WAIT 默认两个传送时间,防止对方让我重传)就可以释放资源了。服务端收到ACK同样等待一段时间后就可以释放资源。

任何一方都可以发起断开连接请求。

耳听为虚眼见为实,使用tcpdump抓包看一下这个过程

1
$ tcpdump -nn -i eth0 port 80

https://gitee.com/lienhui68/picStore/raw/master/null/20200829204330.png

客户端使用curl 模拟三次握手,四次挥手过程

https://gitee.com/lienhui68/picStore/raw/master/null/20200829204400.png

连接过程详情:

https://gitee.com/lienhui68/picStore/raw/master/null/20200829204422.png

页面内容是1400+1381这么大, 分成两个数据包发送

最上面3次握手,中间内容传输,下面是4次挥手

https://gitee.com/lienhui68/picStore/raw/master/null/20200829204735.png

1500个字节,抛开协议头大小,就是1400

tcpdump 可以使用-X显示数据包详情

https://gitee.com/lienhui68/picStore/raw/master/null/20200829205201.png

ddos 分布式拒绝服务

在全球抓一些肉鸡,给对方发第一个包,不发送最后一个确认包,消耗对方资源。一般是通过 规则数据库 特征抽取, 建立黑名单进行防范。

网络层

传输层产生的握手包如何发出去?

多个网卡, 从哪发出去 ip route

什么是ip?

1
172.17.0.1

ip由两部分网络号 和 序号 组成,ip和掩码与运算得到 网络号,网络号是由网卡eth0配置的,连到一个局域网,这台机器是这个局域网的第多少号(序号)机器,同一个局域网网络号不会变。同一个网络号的机器只需要经过交换机(第二层链路层)交换数据不通过路由器。

掩码

网关 下一跳, 大门

把世界所有的设备节点信息保存到内存 组成网络拓补结构,根据图计算最小路径?

使用另一种方式,不安全的传递机制,下一跳

路由器,route -n 得到路由表

https://gitee.com/lienhui68/picStore/raw/master/null/20200829212158.png

172.17.0.1就是下一跳

ping www.baidu.com,

https://gitee.com/lienhui68/picStore/raw/master/null/20200829212357.png

数据包从哪发出去?

目标地址180.101.49.11路由表的掩码进行与运算,255.255.0.0 得到180.101.0.0没匹配上, 换成0.0.0.0 匹配上。所以172.17.0.1就是这个数据包的下一跳,也就是路由器的地址。

再比如ping局域网里的一台机器

https://gitee.com/lienhui68/picStore/raw/master/null/20200829212925.png

和255.255.0.0与运算匹配上,下一跳是0.0.0.0,不需要网关不需要下一跳,网关直接转发出去就行。转发不走网关,公网就得走网关。

ip协议层做了两件事, ip协议中 数据包 目标ip 180.101.49.11, 并且选择下一跳(网关)172.17.0.1

链路层

如果没有链路层,得把世界所有的设备节点信息保存到内存 组成网络拓补结构,根据图计算最小路径。现在只需要记录下一跳的mac地址即可。

链路层协议arp

arp -d是ARP协议中bai删除ARP缓存列表的命令,du可以删除所有的ARP缓存,也可以删除指定的ARP缓存。zhi

ARP协议是将目标IP地址dao映射为目标MAC地址的协议,其在协议上使用ARP请求及ARP应答报文来实现。例如arp -a命令是显示ARP缓存的命令命令,它可以显示电脑上所有的ARP缓存条目。

https://gitee.com/lienhui68/picStore/raw/master/null/20200829214036.png

https://gitee.com/lienhui68/picStore/raw/master/null/20200829214145.png

到链路层,既有传输层的端口号又有网络层的ip地址,还有链路层的mac地址(放的是下一跳的mac地址,由网关广播然后局域网中的各台进行设置)

端点间通信,数据包是在节点间传递,跳跃

每个三层设备都有自己的路由表,都存放着下一跳的mac地址

路由器的目标mac地址换成运营商的mac地址。目标ip地址不变,目标mac地址会变化,像是一个链表,所以叫链路层。

https://gitee.com/lienhui68/picStore/raw/master/null/20200829214943.png

DNS 域名通过DNS转换为IP

mac地址全球唯一, 可以刷,只要在一跳之内mac地址唯一不重复即可。

如果没有目标mac地址,需要走arp协议请求mac地址。

1
arp -d 192.168.3.76 && curl www.baidu.com

https://gitee.com/lienhui68/picStore/raw/master/null/20200829221249.png

会先请求下一跳mac地址,放入自己的arp 缓存列表中。

物理层

网卡的事情,电 波 光 ,信号

小结

多层映射,唯一路径

一个进程会线程创建一个socket

多个socket对应一个进程或一个线程 就是 多路复用器 epoll

应用层让内核创建一个连接,

传输层 握手包

网络层 下一跳的ip地址

mac层 下一跳的mac地址

物理层 电 光 波 信号


高并发 负载均衡

七层 ngix 基于反向代理的负载均衡,往后代的时候解决高并发,后面可以有几千台服务器。ngix 握手, ngix节点支持的连接数比tomcat多。

四层 LVS 不能破坏连接(一对资源)的原子性,握手还是客户端和服务端握手。LVS不握手 只负责数据包转发。

LVS 负责维护客户端和服务端连接的全声明周期,监控、偷窥、记事本。 负载均衡算法。

https://gitee.com/lienhui68/picStore/raw/master/null/20200829222306.png

没有并发就没有juc、负载均衡,就不用考虑是每请求每连接还是连接复用,连接是否要加锁,连接池,是否要用threadlocal。

网络 分布式 微服务 服务治理 service mesh。

mmap RandomAccessFile