目录
- 一、OSI七层模型
- 二、TCP/IP四层模型
- 1.访问网页的全过程
- 2.应用层
- 2.1 HTTP/1.1
- 2.1.1 特点
- 2.2.1.1 无状态
- 2.2.1.2 明文传输
- 2.2.1.3 管道传输
- 2.1.2 URL结构
- 2.1.3 常见字段
- 2.1.4 状态码
- 2.2 HTTPS
- 2.2.1 混合加密
- 2.2.2 HMAC哈希值
- 2.2.3 数字证书
- 2.3 HTTP2
- 2.4 HTTP3
- 2.5 WebSocket
- 2.5.1 实现消息推送
- 2.6 DNS
- 2.6.1 重定向
- 2.6.2 请求转发
- 2.7 其他协议
- 2.7.1 SMTP、POP3/IMAP
- 2.7.2 FTP
- 3.传输层
- 3.1 TCP
- 3.2 TCP与UDP区别
- 3.3 三次握手
- 3.4 四次挥手
- 3.5 Socket编程
- 3.5.1 过程(联系redis网络I/O)
- 4.网络层
- 4.1 NAT
- 4.2 ARP
- 5.物理层
一、OSI七层模型
物链网输话示用:
二、TCP/IP四层模型
物网输用:
1.访问网页的全过程
假设网络拓扑:主机A(子网1) → 路由器R1(局域网端口p1,局域网端口p2,广域网端口p) → 路由器R2 → ... → 路由器Rn(主机B的网关) → 主机B(子网N)
- 主机A发送HTTP请求
https://www.badu.com/到主机B,首先向本地DNS服务器发送DNS请求,用于获取目的IP。 - 本地DNS服务器如果没有缓存www.baidu.com的IP,那么首先会访问根DNS服务器询问com顶级DNS服务器的IP,然后访问顶级DNS服务器的IP询问baidu.com权威DNS服务器的IP,然后访问权威DNS服务器询问www.baidu.com的IP,并在DNS表中记录
<域名,IP>,将目的IP返回给主机A。 - 主机A根据
子网掩码判断主机B不在该局域网内,所以需要将请求发送给路由器。 - 主机A需要局域网内路由器端口p1的MAC,所以使用ARP向局域网内的所有主机广播R1路由器p1的IP,端口p1接收到广播后单播响应自己的MAC给主机A。
- 主机A在ARP表中记录
<IP,MAC>,封装报文{主机A的局域网IP,主机B的广域网IP,主机A的MAC,路由器端口p1的MAC,发送的数据},发送给端口p1。 - 由于当前报文是局域网IP,不同局域网之间会重复,所以路由器R1创建一个唯一的端口PortA,在NAT表中记录
<主机A的局域网IP:Port,广域网IP:PortA>。 - 路由器R1查询路由表
<IP,子网掩码,下一跳>,选择与主机B的广域网IP位于同一子网的路由器R2的IP,基于ARP发送IP获取R2的MAC。 - 修改报文
{主机A所在局域网的广域网IP:PortA,主机B的广域网IP:Port,路由器R1端口p的MAC,路由器R2的MAC,发送的数据},将报文发送给下一跳R2。 - R2同理查路由表找到IP,使用ARP获取MAC,修改报文的源MAC和目的MAC发送给Rn。
- Rn接收到报文,检查目的IP是自己,这表示当前的报文是发给该局域网内的主机的,路由器Rn检查NAT表获取主机B的局域网IP,检查ARP表获取主机B的MAC地址修改报文
{主机A的共享广域网IP:PortA,主机B的局域网IP:PortB,路由器Rn的MAC,主机B的MAC,发送的数据},发送给主机B。 - 主机B收到报文。
- 三次握手也是上述流程,只不过不封装HTTP直接使用TCP。
2.应用层
应用层是工作在操作系统中的用户态,传输层及以下则工作在内核态。
每个进程对应一个端口,传输层就是在2个端口之间之间传输HTTP报文。
2.1 HTTP/1.1
基于TCP协议在Web服务器之间传输文本、图片、音频的协议,因此发送 HTTP 请求之前要三次握手建立TCP连接。
客户端向服务器发送 HTTP Request,服务器响应请求并返回 HTTP Response。HTTP协议只支持客户端主动请求,服务端被动响应。
2.1.1 特点
2.2.1.1 无状态
HTTP 协议本身是无状态的,这意味着服务器默认情况下无法区分两个连续的请求是否来自同一个用户,或者同一个用户之前的操作是什么。
所以一般手动配合Cookie和Session进行信息保存。服务器为建立TCP连接的用户创建一个专属的Session session = getSession()对象,并分配一个唯一的SessionID。服务器编辑响应报文时将SessionID写入响应头中的Set-Cookie字段发送给用户的浏览器。浏览器接收到SessionID后保存在浏览器内存,后续每次向该服务器发请求,浏览器都会自动带上SessionID。服务器收到请求后,根据SessionID就能找到对应的Session对象,从而知道这是哪个用户以及他之前的状态了。
2.2.1.2 明文传输
HTTP信息是明文传输,报文格式是Head+Body,头部信息key-value存储,通过wireshark可以直接看到数据。
2.2.1.3 管道传输
管道传输指的是客户端可以连续发送多个请求,不必等待上一个请求返回响应,减少响应时间,服务器必须按照接受请求的顺序返回响应。
注意,管道化技术默认不开启,而且浏览器基本都没有支持。
2.1.2 URL结构
协议、域名:IP的可读版本、端口、资源路径、参数:用于Get请求、锚点
2.1.3 常见字段
Host:指定目标服务器的域名Content-Length:服务器返回数据的长度B。Connection:Keep-Alive默认保持连接。Accept:客户端能接受的返回值类型。Content-Type:服务器实际返回的数据类型。Accept-Encoding、Content-Encoding:客户端能接受的数据压缩方法、服务器实际使用的数据压缩方法。
2.1.4 状态码
2XX:成功状态码200 OK:请求被成功处理,服务器正确返回了数据。201 Created:请求被成功处理,创建了新的资源。202 Accepted:服务器接收到请求但是还未处理。204 No Content:服务器成功处理请求,单位返回任何数据。
3XX:重定向状态码301 Moved Permanently:资源被永久重定向了,网站的网址更换了。302 Found:资源被临时重定向了,网站的某些资源被暂时转移到另外一个网址。
4XX:客户端错误状态码400 Bad Request:发送的 HTTP 请求存在问题。401 Unauthorized:未认证却请求需要认证之后才能访问的资源。403 Forbidden:请求被拒绝,一般用来针对非法请求。404 Not Found:请求的资源未在服务端找到。409 Conflict:请求的资源与服务端当前的状态存在冲突,请求无法被处理。
5XX:服务器错误状态码500 Internal Server Error:服务端出问题了。502 Bad Gateway:网关将请求转发到服务端,但是服务端返回的却是一个错误的响应。
2.2 HTTPS
HTTPS在TCP和HTTP之间加入了SSL安全协议,使得报文能够加密传输,防止数据被窃取、数据被篡改、服务器被冒充。
HTTPS在TCP三次握手之后,还需进行TLS握手,才可进入加密报文传输。
2.2.1 混合加密
混合加密主要是防止数据被窃取,HTTPS在TCP三次握手之后,还需进行SSL/TLS的握手过程,才可进入加密报文传输,具体过程如下:
- 客户端发送一个随机数Random1。
- 服务器接收Random1并返回一个随机数Random2、数字证书、公钥。(服务器持有一个私钥和一个公钥,公钥可以任意分发而私钥保密)
- 客户端验证服务器的数字证书核实身份,生成一个46B的随机数preMasterSecret,使用公钥加密后发送给服务器。
- 服务器使用私钥解密得到preMasterSecret。
- 此时客户端和服务器分别持有相同的Random1、Random2、preMasterSecret,各自使用PRF生成主密钥,然后分割成客户端/服务器的加密秘钥/MAC秘钥,使用这些秘钥保证数据的加密传输。
综上,在握手阶段采用非对称加密保证preMasterSecret加密传输,握手完成后采用对称加密基于秘钥块加密传输。
2.2.2 HMAC哈希值
HMAC是为了为了防止传输过程中数据被篡改。
客户端发送数据时,会先将数据使用客户端MAC秘钥计算哈希值,然后拼接明文数据和哈希值,使用客户端加密秘钥加密数据。
服务器接收到数据后,首先使用服务器加密秘钥解密数据,然后分理处明文数据和哈希值,使用服务器MAC秘钥计算哈希值,通过判断两个哈希值是否相同确定数据是否被篡改。
2.2.3 数字证书
数字证书防止服务器被冒充,HTTPS协议需要向CA(证书权威机构)申请数字证书,来保证服务器的身份(公钥)是可信的。
2.3 HTTP2
HTTP/2协议是基于HTTPS的,能保证数据安全。
- 基于HPACK算法在客户端和服务器同时维护一张Head表<Head, index>,对于相同的Head只发送索引,减少了重复发送冗长的Head。
- 直接发送二进制的Head+Body数据。
- HTTP/1.1一次只能发送一个HTTP请求,接收响应后才能继续发送,主要是为了保证请求的有序性,但会有对头阻塞问题。HTTP/2将TCP链接划分成多个Stream,每个Stream视作一条HTTP请求。有唯一的StreamID,可以一次性发送多个请求/返回多个响应,返回响应时必须按照StreamID的顺序返回HEADERS帧,DATA帧可以任意交错。(并发问题在应用层控制,这里不要搞混了)
- 客户端和服务器双方都可以建立 Stream,HTTP/2推送允许服务器在客户端请求一个资源时,主动将其他资源推送给客户端。例如,当客户端请求一个 HTML 页面时,服务器可以主动推送该页面所需的 CSS 和 JavaScript 文件。
2.4 HTTP3
HTTP2虽然解决了HTTP层的对头阻塞问题,但仍然有TCP层的对头阻塞问题,这是由于TCP层的角度并没有多Stream,所有数据都是通过单通道TCP有序传输的,此时如果Stream1(HTTP)的数据在队首,等待Steam1的剩余数据包到达,后面排队的Stream3、Stream5即使数据包都到达了也必须等待。
HTTP3基于HTTP2的多Stream概念,通过将TCP换成UDP解决传输层的对头阻塞问题。通过QUIC保证UDP的可靠传输。当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响,因此不存在队头阻塞问题。
2.5 WebSocket
基于TCP连接,客户端和服务器可以同时发送和接收数据,用于解决HTTP协议只支持单向请求、以及在长时间通信能力的不足。客户端和服务器仅需一次握手,建立连接过程如下:
- WebSocket请求基于HTTP协议,三次握手建立TCP连接后,客户端向服务器发送一个HTTP请求,请求头中包含
Upgrade: websocket、Sec-WebSocket-Key等字段,表示要求升级协议为WebSocket。 - 服务器收到请求后,回复
HTTP 101状态码,响应头中包含Connection: Upgrade、Sec-WebSocket-Accept: xxx等字段、表示成功升级到WebSocket协议。 - 建立WebSocket连接后,客户端和服务器都可以主动发送请求。
- 建立WebSocket连接之后,通过心跳机制来保持WebSocket连接的稳定性和活跃性
2.5.1 实现消息推送
客户端(前端)通过ws://localhost:7777/webSocket/10086与服务器建立WebSocket连接,用户A与用户B通信时,两个客户端都要与服务器建立WebSocket连接,然后用户A将消息发送给服务器,服务器接收到用户A的消息后将消息发给用户B。这应该就是QQ和微信实时接收消息的逻辑。
@ServerEndpoint注解的优先级比@Component高,所以会为每个WebSocket链接建立一个单例对象,因此每个链接独占session和userId成员变量。而将webSocketSet和sessionMap设置为static保证该类的所有WebSocket对象共享该static变量。(这也是static的作用)- 客户端A发送消息后会自动执行服务器中客户端A与服务器建立的WebSocket对象的
onMessage(message)方法,我们可以在方法内编写将message发送给客户端B的逻辑,可以规定message前16个字符为目标客户端的id,这样sessionMap.get(message.substring(16)).getAsyncRemote().sendText(message)就可以将消息发给客户端B了。
@Component@Slf4j@ServerEndpoint("/websocket/{userId}")publicclassWebSocketServer{// 当前连接的会话privateSessionsession;// 当前连接的用户IDprivateStringuserId;// 存储所有活跃的WebSocket连接实例(线程安全)privatestaticfinalSet<WebSocketServer>webSocketSet=newCopyOnWriteArraySet<>();// 存储用户ID和对应Session的映射(改用线程安全的ConcurrentHashMap)privatestaticfinalMap<String,Session>sessionMap=newConcurrentHashMap<>();/** * 连接建立成功调用的方法 */@OnOpenpublicvoidonOpen(Sessionsession,@PathParam("userId")StringuserId){this.session=session;this.userId=userId;webSocketSet.add(this);sessionMap.put(userId,session);}/** * 连接关闭调用的方法 */@OnClosepublicvoidonClose(){// 移除当前连接的实例和session映射webSocketSet.remove(this);sessionMap.remove(this.userId);}/** * 收到客户端消息调用的方法 */@OnMessagepublicvoidonMessage(Stringmessage,Sessionsession){// 向客户端A返回发送成功sendOneMessage(this.userId,"已收到消息:"+message);// 向客户端B发送消息,message.substring()截取客户端b的id,前提是规定前16个字符是目标客户端IDsendOneMessage(message.substring(16),"来自客户端A的消息:"+message);}/** * 单点推送:向指定用户发送消息 * @param userId 目标用户ID * @param message 推送内容 */publicvoidsendOneMessage(StringuserId,Stringmessage){SessiontargetSession=sessionMap.get(userId);// 异步发送消息(非阻塞)targetSession.getAsyncRemote().sendText(message);}/** * 广播推送:向所有在线用户发送消息 */publicvoidsendBroadcastMessage(Stringmessage){for(WebSocketServerwebSocket:webSocketSet){webSocket.session.getAsyncRemote().sendText(message);}}}2.6 DNS
基于UDP协议管理域名和IP地址的映射。
浏览器在本地会维护一个hosts列表,如果本地hosts列表内没有域名-IP对应记录的话,那么就需要DNS。
- 本地DNS服务器:当主机发出DNS请求时会首先被发往本地DNS服务器,起到代理的作用。
- 根DNS服务器:提供顶级DNS服务器的IP地址
{<com, ip>,<org, ip>...}。 - 顶级DNS服务器:每个服务器对应一个
com、org、net、edu后缀,记录该后缀下的二级IP地址{<a.com, ip>,<b.com, ip>...}。 - 权威DNS服务器:记录三级IP地址,对应每台主机。
2.6.1 重定向
主机cis.poly.edu想知道gaia.cs.umass.edu的IP地址:
- 首先发送给本地DNS服务器代理查询。
- 本地DNS首先向根DNS服务器查edu的顶级DNS服务器IP。
- 本地DNS向edu的顶级DNS服务器查umass.edu的权威DNS服务器IP。
- 本地DNS向umass.edu的权威DNS服务器查gaia.cs.umass.edu对应的主机IP。
2.6.2 请求转发
2.7 其他协议
2.7.1 SMTP、POP3/IMAP
SMTP基于TCP协议发送电子邮件、 POP3/IMAP基于TCP协议接收电子邮件,所以也需要三次握手确保可靠性。
- 向邮箱服务器发送SMTP请求,将邮件交给163邮箱服务器。
- 163邮箱服务器发现我发送的邮箱是QQ邮箱,然后使用SMTP协议将邮件转发到QQ邮箱服务器。
- QQ邮箱服务器接收邮件之后就通知目标用户来收邮件,目标用户通过POP3/IMAP协议将邮件取出。
2.7.2 FTP
基于TCP协议传输文件的协议。
3.传输层
负责建立两台设备进程之间的通信。
- TCP:提供面向连接的、可靠的数据传输服务。
- UDP:提供无连接的、尽最大努力的数据传输服务,不保证可靠性。
3.1 TCP
通过源IP:源端口+目的IP:目的端口确定唯一的TCP连接。
3.2 TCP与UDP区别
- TCP要建立连接才能发送数据,UDP可以直接发送数据。
- TCP通过SEQ、ACK、重传等机制保证数据有序不丢失,UDP不保证数据数据到达的顺序。
- TCP需要维护连接状态,UDP发完即走不关心数据是否达到,速度更快。
- TCP只支持点对点,UDP支持一对多(多播)、多对多(广播)。
- TCP头部占用20~60B,UDP只占8B。
3.3 三次握手
TCP依赖序列号(SEQ)与确认号(ACK)实现可靠传输,发送方发送seq=x,接收方发送ack=x+1回复x+1之前的序列都已经收到,保证了数据有序不丢失。
服务端收到SYN并返回SYN+ACK后,连接进入SYN_RCVD,等待客户端最终ACK。如果一直收不到 ACK,内核会按重传策略重发SYN+ACK,超时则清除该连接。
为什么要三次握手而不是两次?第二次握手保证了Server对Client从哪一个序号开始收发数据达成一致,第三次握手是为了保证Server的seq序列号同步,使Client对Server“从哪一个序号开始收发数据”达成一致,所以第三次握手只是为了确认ack,所以seq可以携带数据。
3.4 四次挥手
前两次挥手是为了确保Client端的seq数据在Server端全部接收到;后两次挥手是为了确保Server端的seq数据在Client端全部接收到。
发送FIN表示不能发送数据了但是还能接收数据,由于服务器发送ACK后可能还会向客户端发送消息,发送完数据后才会发送FIN,所以无法合并服务器端的两步操作。(当服务器接收到客户端的FIN并自己也没有数据要发送给客户端时,四次挥手会变成三次)
3.5 Socket编程
3.5.1 过程(联系redis网络I/O)
- 服务端创建监听Socket,得到文件描述符fd,调用bind将socket绑定到指定的IP和端口,调用listen监听。
- 客户端创建Socket,得到文件描述符fd,调用connect阻塞向服务器指定IP和端口发起TCP连接SYN请求,得到ACK+SYN后唤醒。
- 服务端accept阻塞等待客户端第三次握手ACK后唤醒,为客户端建立连接Socket。(accept系统调用只是负责从TCP全连接队列取出已经建立连接的Socket,不参与三次握手过程)
- 客户端调用write发送HTTP请求,服务端调用read接受请求。
- 服务端处理请求,调用write发送HTTP响应给客户端。
- 客户端断开连接时调用close,服务端read会读到EOF并返回ACK,待处理完数据后调用close并等待ACK,连接关闭。
4.网络层
将报文段封装成IP数据报,路由找到目标主机。
- IP:定义数据包的格式,每个连接互联网的设备都会被分配唯一的IP,ipv4 32位,ipv6 128位。
- ARP:管理IP逻辑地址和物理层MAC物理地址之间的映射。
- NAT:管理局域网IP到广域网IP的映射。
- OSPF:动态路由协议,基于链路状态算法,考虑链路的带宽、延迟等因素来选择最佳路由路径。
- RIP:动态路由协议,基于距离向量算法,选择跳数最少的路径作为最佳路由路径。
- ICMP:传输网络状态和错误消息。
4.1 NAT
局域网内主机的IP是局域网IP,也就是说不通局域网之间的主机IP会重复,这样是为了避免IPV4耗尽。同一局域网内的所有主机都使用同一个广域网IP与其他局域网之间的主机进行通信。
**一台路由器有多个端口,每个端口都有各自的IP和MAC。
- Wan口用于局域网内的主机与外部Internet通信,只有一个。
- 有多个LAN口,每个LAN口都是一个局域网。
NAT表一个路由器只有一张,用来记录<局域网IP:Port,广域网IP:Port>的映射关系,请求到达路由器时,由于携带的是Wan口的IP,所以就要通过NAT表根据端口找到目的主机。
- 局域网中
10.0.0.1~10.0.0.4都是局域网IP,局域网内部的通信可以直接使用局域网IP。 - 但是由于不同局域网之间IP会重复,所以局域网中的四台主机共享
138.76.29.7这个一个广域网IP,主机10.0.0.1:port1发送HTTP请求时如果目的IP地址是局域网外的IP,那么路由器将为该请求创建一个在NET中不重复的端口号port2,并使用138.76.29.7:port2向外部网络发送HTTP请求,并在NAT表中记录<138.76.29.7:port2,10.0.0.1:port1>,方便响应返回时路由器知道发给局域网内的哪台主机。
4.2 ARP
MAC地址的长度为6B,是一个网络设备真正的固定身份标识,IP地址只是可变的一种不重复的身份标识。路由器具有多个端口,每个端口都有IP和MAC地址且各自维护一个ARP表记录了该局域网内其他网络设备的IP-MAC映射关系。
当请求到达路由器某个端口时,根据子网掩码判断目标主机在该端口对应的局域网内,由于路由器端口只知道局域网内主机的IP,并不知道MAC,所哟需要FF-FF-FF-FF-FF-FF广播发送ARP请求给局域网内的所有主机,携带目标MAC地址,对应的主机接收到请求后返回ARP响应给路由器端口,这样路由器端口就知道将请求发送给哪个主机了,并将缓存信息记录到ARP表中。
5.物理层
在相邻计算机节点之间传送比特流。