重温计算机网络基础

349 阅读12分钟

TCP/IP参考模型分层

功能 地址,通信实体 常见协议 转发设备
应用层 电子邮件,P2P, WEB, 文件传输,远程终端 各用户进程 POP3, SMTP, HTTP, FTP, TELNET,DNS
传输层 流量控制,拥塞控制,可靠传输等 ip:port, 传输的是TCP报文段或是UDP数据报,进程间通信 TCP/UDP 网关
网络层 路由规划 ip, 主机间通信,ip数据报 IPv4/v6, ARP, DHCP(封装成 UDP数据报在应用层实现),NAT,ICMP, RIP, OSPF, BGP 路由器
数据链路层 通过一条链路从一个节点向另一个物理链路直接相连的相邻节点传送数据报,可能有流量控制、差错检测、差错纠正、全/半双工通信。 MAC地址(通过ARP协议获取),传输数据帧 信道划分MAC(TDMA/FDMA/CDMA/WDMA),随机访问MAC协议(sloted ALOHA, ALOHA, CSMA, CSMA/CD, CSMA/CA ),轮转访问MAC(令牌传递,蓝牙,令牌环网) 网桥/桥接器
物理层 比特流 转发器

TCP / UDP 区别

TCP:

  1. 运输协议数据单元TPDU为TCP报文段。
  2. 面向连接,传输数据之前需要进行三报文握手,断开连接要进行四报文挥手。
  3. 每一条TCP连接只能有两个端点,每一条TCP连接只能是点对点的。
  4. 首部20个字节,较大。
  5. 面向字节流,根据对方给出的窗口和网络拥塞程度决定一个报文应该包含多少个字节。而UDP发送的报文段长度就是应用进程给出的。

UDP:

  1. TPDU为UDP用户数据包。
  2. 无连接服务,传送数据之前不需要建立连接。远程主机收到UDP数据包后也不需要给出任何确认。
  3. 支持一对一、一对多、多对一和多对多的交互通信。
  4. 首部8个字节,较小。
  5. 面向报文,UDP对应用层交下来的报文既不拆分也不合并,保留边界,加上首部和IP首部就直接成了一个IP报文段。

共同点:

  1. 都支持全双工通信

TCP 可靠传输

  1. 停等ARQ(auto repeat reQuest)协议

发送端发送一个分组,接收端收到并返回一个确认,发送端收到确认才能继续发送下一个分组。 如果等待确认超时,那么自动重新发送这个报文,并重启它的计时器。

  1. 连续ARQ协议

发送方维护一个滑动窗口,每当收到接收端发来的一个确认,就将这个窗口往前拓展。 接收方的确认是累计确认,不必对收到的每个分组都发送确认,而是对按序到达的最后一个分组发送确认。这样可以减小传输的开销。 因此,它不能向发送端反应已经正确接收到的所有分组信息。因此发送端可能需要GBN重传。

TCP 流量控制

连接建立的时候也会协商发送和接收的窗口大小。 后续动态的流量控制可基于滑动窗口轻松实现。

TCP 拥塞控制

慢开始

发送方每收到一个对新报文段的确认就使拥塞窗口加1,这样没经过一个传输轮次,拥塞窗口就会加倍。 拥塞窗口是一个指数增长的过程。 之所以说是慢开始,不是说他的增长速率,而是说它初始的拥塞窗口仅设置为1-2个发送方的最大报文段。

拥塞避免

慢开始不可能让拥塞窗口无限的增长下去,因此设置一个慢开始门限(ssthresh)。 当慢开始算法执行到门限时,改用拥塞避免算法。 每经过一个RTT,就让窗口加1,这时拥塞窗口的增长是线性的。 当网络中出现超时的情况,判断网络中出现了拥塞,将ssthresh调整为当前拥塞窗口的一半。之后启用慢开始算法。

快重传

当收到三个重复确认时,立即重传,这样就不会出现超时,因此也不会被误认为网络拥塞。

快恢复

在3个重复确认时,发送方知道现在只是丢失了个别的报文段,并不一定是网络拥塞,因此不启动慢开始,而是启动快恢复。

将ssthresh调整为当前拥塞窗口的一半,并直接开始执行拥塞避免算法。

TCP 连接建立 -- 三报文握手

首先服务端开启某个端口的监听,处于LISTEN状态。等待客户端发来建立连接的请求。

这时客户端可能是用户在浏览器点击了某个链接,主动打开了TCP的连接,向目的客户端发送一个请求建立连接的TCP报文段。

服务器收到这个报文段会发出同意建立连接的报文,带上对请求的报文段的ack = seq + 1字段。此时服务端进入SYN-RECV同步已接受状态。等待接收客户端对本确认确认的报文。

在客户端收到服务端确认报文段之前都处于SYN-SENT同步已发送状态。

一旦客户端收到服务端的确认报文,就已经进入ESTABLISHED状态,已经可以向服务端发送数据了。

但此时服务端还在等待来自客户端的确认,因此会稍晚于客户端进入ESTABLISHED状态。

为什么客户端最后还要再发送一次确认呢?

主要是为了防止之前已经失效的连接请求报文突然又传送到了服务端,而服务端误以为是客户端新的连接请求。因此它向客户端发送确认,新的连接就建立了。而客户端并不会发送新的数据,浪费了连接的资源。

TCP 连接释放 -- 四报文挥手

通信结束后双方都可以选择关闭连接,假设客户端主动关闭连接。

客户端会首先发送一个连接释放的报文段,首部的FIN字段设置为1,表明这是一个终止连接的报文段。进入FIN_WAIT1状态,直到收到服务端发来的确认报文段。

服务端收到关闭连接的请求报文段后就会进入CLOSE-WAIT状态。这时处于一种半关闭的状态。客户端向服务端的连接已经结束了,客户端本身也没有要发的数据了。而服务端还可以通知应用进程,判断是否还有需要向客户端发送的消息,如果有,还可以持续的发送一段时间。

当应用进程不需要再发送数据时,会主动向客户端发送一个终止的报文,首部FIN字段为1。随后进入LAST-ACK状态。

当客户端收到这个终止报文后FIN-WAIT2状态结束。向服务端发出最后的一个确认报文。随后进入到2分钟的TIME_WAIT状态定时结束后,该连接相关的资源在客户端就已经被彻底释放。

而服务端一旦收到最后的确认报文,就可以立即释放掉相关的资源进入到CLOSED的状态。

为什么客户端必须等待2分钟呢?

  1. 保证刚刚发送的确认能到达服务端,让服务端根据这个报文能够正常的关闭连接。如果在这两分钟之内,服务端没有收到客户端的最后确认,会重传它的终止报文。

  2. 为下一次新的连接考虑。让已经失效的连接在这两分钟内全部都从网络中消失。这样下一个连接建立的时候就不会有这种旧的连接请求报文。

DNS 查询步骤

  1. 查看本地缓存(浏览器,操作系统 /etc/hosts)
  2. 操作系统将这个域名发送给配置好的LDNS(本地域名服务器)。这个服务器性能很好,有大量缓存,80%的域名解析到这里就已经完成了。
  3. 如果LDNS都没有命中,就会用以下的方式一层一层的请求,根域名服务器、顶级域名服务器。最后会返回一个IP地址,和一个TTL。LDNS会根据这两个值设置缓存。
  4. 实际可能还会有链路的负载均衡。

两种方式:

另外,在JVM中也会有缓存(InetAddress中),因此在使用InetAddress类解析域名时必须是单例模式。否则每次创建InetAddress都会进行一次完整的域名解析,非常耗时。

网络层路由策略

RIP 基于距离向量算法的路由协议

OSPF 基于Dijkstra算法的路有协议

毒性反转

HTTP

连接建立之后 , 客户端发送 HTTP 请求到服务端与请求相关的信息都会包含在请求头和请求体中发送给服务器端 .

服务器端在收到请求之后 , 根据客户端的请求发送给客户端相应的信息 , 相关的响应信息都会放在响应头和响应体中 .

服务器端在发送完响应之后 , 就会关闭连接 , 如果过客户端的请求的头部信息中有 Connection: keep-alive , 那么客户端在响应完这个请求之后不会关闭连接 , 直到客户端的所有请求都响应完毕 , 才会关闭连接 , 这样大大节省了带宽和 IO 资源 .

HTTP请求头和响应头字段

Request Header

Accept: text/html --> 浏览器可以接受的媒体类型(MIME)

Accept-Encoding:gzip, deflate --> 可以接受的压缩类型

Accept-Language: zh-CN;en; --> 可以接受的语言类型

Accept-Charset:--> 可以接受的编码类型

需要解析Accept-Charset字段,根据这个值,来设定采用的编码方式。 服务器端以原生的Servlet & JSP为例: 1)当返回的是HTML页面,那么页面meta charset就指定了编码格式 2)当返回的是JSP页面,那么页面pageEncoding就指定了编码格式 3)当通过resp的Outputstream返回原生内容时,我们可以通过设置响应头content-type/content-charset字段来指定编码格式

Host:--> 用于指定被请求资源的主机和端口号 User-Agent:--> 客户端将它的操作系统,浏览器和其他属性告诉服务器

Connection:keep-alive--> 关于TCP连接释放的约定。直到客户端的所有请求都响应完毕,才会关闭连接, 这样大大节省了带宽和IO资源。

Cache-Control: no-cache --> 控制缓存的具体策略常见有no-cache, no-store, max-age.该字段的优先级较高,可能覆盖其他的字段的值。

比如,请求报文头中有cache-control:no-cache,那就表示,代理如果返回给我缓存文件时,需要到服务器端进行确认,缓存是不是最新的。

比如,请求报文头中有cache-control:no-store,那就表示,我不需要代理中的缓存文件,我需要直接请求服务器。

比如,响应报文中有Cache-Control:max-age=500,表示在接下来的500秒内,浏览器可以自主使用缓存内容,不需要向服务器发送同样的请求。

Pragma: no-cache --> 与Cache-Control 类似。

Response Header

Server: nginx/1.14.0--> 服务端的服务器名称 Content-Type--> 内容的类型

Last-Modified/ETag --> 浏览器一般只对.html,.jpg,.css,.js等这些静态资源进行缓存,对于jsp页面以及ajax请求的动态结果,不缓存。服务器如Tomcat会自动给静态文件的响应报文添加“Last-Modified”字段,同时解析请求报文中的If-Modified-Since字段。如果客户端缓存的页面是最新的,就返回状态码304告诉客户端是最新的,服务器也不会传输新的数据。

常见状态码

405(Method Not Allowed) 请求的方法不合法

304(Not Modified) 表示所请求的资源未修改,服务器返回此状态码时不会返回任何资源

302(Found) 临时重定向,表示请求的资源临时搬到了其他位置 --> response.sendRedirect()方法会返回该状态码

400(Bad Request) 客户端请求的语法错误,服务器无法理解

403(Forbidden) 服务器理解客户端的请求,但是拒绝执行此请求 --> linux下对tomcat文件夹的访问权限不够会返回该状态码

100 (Continue) 服务器接收了试探性的request header,确认可以接受,这时客户端可以开始发送request body,多出现在POST方法中

HTTPS

实际上就是在HTTP下面,TCP上面还有一个安全套接字层SSL(Security Socket Layer)。 在通信过程中会用到公钥和私钥来加密传送的信息。

采用HTTPS的服务器需要申请一套数字证书,这套证书其实就是一对公钥和私钥。

对客户端来说HTTPS的默认端口是443,发送请求后会传送到服务器的443端口。

服务端会传送一个证书回来,不包含私钥,包含了公钥和颁发机构,过期时间等。 客户端对这个证书进行验证。验证合法,就生成一个随机值,通过公钥加密后传送给服务器。

这个随机值只能用私钥解密才能获取,因此只有真正的服务器才能拿到这个随机值。

到目前为止,双方的通信都是非对称加密的,过程较为复杂。

之后它们就可以使用这个随机值进行对称的加密,正常通信。