本文参考 JavaGuide

网络

常见网络模型

  • OSI七层模型:如下。
  • TCP/IP四层模型:如下。
  • 混合模型:混合模型结合了OSI模型和TCP/IP模型的优点,以更好地解释和实现网络通信。
    • 五层模型: 物理层、数据链路层、网络层、传输层和应用层。 去除了OSI模型中的会话层和表示层,将它们的功能合并到应用层中。
  • IEEE 802模型:主要用于局域网(LAN)和城域网(MAN)。包含物理层和数据链路层,进一步细分为介质访问控制(MAC)层和逻辑链路控制(LLC)层。

OSI七层模型

  • 应用层:为计算机提供服务
  • 表示层:数据处理(编码、解码、加密解密、压缩解压缩)
  • 会话层:管理(建立、维护、重连)应用程序之间的会话
  • 传输层:为两台主机进程之间的通信提供通用的数据传输服务
  • 网络层:转发、路由和寻址(决定数据在网络中的游走路径)
  • 数据链路层:帧编码和误差纠正控制
  • 物理层:透明地传送比特流传输

TCP/IP四层模型

  • 应用层(应用层、表示层、会话层)
  • 传输层
  • 网络层
  • 网络接口层(数据链路层、物理层)

为什么网络要分层

复杂系统需要分层,每层专注于一类事情。主要有三个原因:

  • 各层之间相互独立,不需要关注其他层如何实现的,只需知道如何调用下层的接口。
  • 提高了灵活性和可替换性。每层可使用最合适的技术实现,只需保证提供的功能及接口没改变就行。这也与平时系统开发高内聚、低耦合的原则契合。
  • 将复杂的网络问题分解为较小的、清晰的小问题来处理解决,使得计算机网络系统易于设计和维护。

常见网络协议

应用层协议

  • HTTP(Hypertext Transfer Protocol,超文本传输协议):基于 TCP 协议,是一种用于传输超文本和多媒体内容的协议,主要是为 Web 浏览器与 Web 服务器之间的通信而设计的。
  • SMTP(Simple Mail Transfer Protocol,简单邮件发送协议):基于 TCP 协议,是一种用于发送电子邮件的协议。
  • POP3/IMAP(邮件接收协议):基于 TCP 协议,两者都是负责邮件接收的协议。IMAP 协议是比 POP3 更新的协议,它在功能和性能上都更加强大。IMAP 支持邮件搜索、标记、分类、归档等高级功能,而且可以在多个设备之间同步邮件状态。
  • FTP(File Transfer Protocol,文件传输协议): 基于 TCP 协议,是一种用于在计算机之间传输文件的协议,可以屏蔽操作系统和文件存储方式。(不安全,更安全可以用SFTP)
  • Telnet(远程登陆协议):基于 TCP 协议,用于通过一个终端登陆到其他服务器。Telnet 协议的最大缺点之一是所有数据(包括用户名和密码)均以明文形式发送,这有潜在的安全风险。
  • SSH(Secure Shell Protocol,安全的网络传输协议):基于 TCP 协议,通过加密和认证机制实现安全的访问和文件传输等业务。
  • RTP(Real-time Transport Protocol,实时传输协议):通常基于 UDP 协议,但也支持 TCP 协议。它提供了端到端的实时传输数据的功能,但不包含资源预留存、不保证实时传输质量,这些功能由 WebRTC 实现。
  • DNS(Domain Name System,域名管理系统): 基于 UDP 协议,用于解决域名和 IP 地址的映射问题,端口为 53。

传输层协议

  • TCP(Transmission Control Protocol,传输控制协议 ):提供 面向连接 的,可靠 的数据传输服务。
  • UDP(User Datagram Protocol,用户数据协议):提供 无连接 的,尽最大努力 的数据传输服务(不保证数据传输的可靠性),简单高效。

网络层协议

  • IP(Internet Protocol,网际协议):TCP/IP 协议中最重要的协议之一,主要作用是定义数据包的格式、对数据包进行路由和寻址,以便它们可以跨网络传播并到达正确的目的地。(IPv4、IPv6)
  • ARP(Address Resolution Protocol,地址解析协议):ARP 协议解决的是网络层地址和链路层地址之间的转换问题(IP 地址转 MAC 地址)。
  • ICMP(Internet Control Message Protocol,互联网控制报文协议):一种用于传输网络状态和错误消息的协议,常用于网络诊断和故障排除。
  • NAT(Network Address Translation,网络地址转换协议):用于内部网到外部网的地址转换过程中。
  • OSPF(Open Shortest Path First,开放式最短路径优先):一种内部网关协议(Interior Gateway Protocol,IGP),也是广泛使用的一种动态路由协议,基于链路状态算法,考虑了链路的带宽、延迟等因素来选择最佳路径。
  • RIP(Routing Information Protocol,路由信息协议):一种内部网关协议(Interior Gateway Protocol,IGP),也是一种动态路由协议,基于距离向量算法,使用固定的跳数作为度量标准,选择跳数最少的路径作为最佳路径。
  • BGP(Border Gateway Protocol,边界网关协议):一种用来在路由选择域之间交换网络层可达性信息(Network Layer Reachability Information,NLRI)的路由选择协议,具有高度的灵活性和可扩展性。

浏览器输入URL到页面展示的过程

  1. 在浏览器中输入指定网页的 URL。
  2. 浏览器通过 DNS 协议,获取域名对应的 IP 地址。
  3. 浏览器根据 IP 地址和端口号,向目标服务器发起一个 TCP 连接请求。
  4. 连接建立后,浏览器在 TCP 连接上,向服务器发送一个 HTTP 请求报文,请求获取网页的内容。
  5. 服务器收到 HTTP 请求报文后,处理请求,并返回 HTTP 响应报文给浏览器。
  6. 浏览器收到 HTTP 响应报文后,解析响应体中的 HTML 代码,渲染网页的结构和样式,同时根据 HTML 中的其他资源的 URL(如图片、CSS、JS 等),再次发起 HTTP 请求,获取这些资源的内容,直到网页完全加载显示。
    • 在解析HTML的过程中,浏览器会遇到外部资源如CSS、JavaScript、图像等,会再次发送请求获取这些资源。
    • 浏览器解析CSS文件,构建CSSOM(CSS Object Model),并与DOM树合并形成渲染树(Render Tree)。
    • 如果有JavaScript代码,浏览器会暂停渲染,先执行JS代码,这可能改变DOM结构和样式。
    • 浏览器计算每个元素的位置和尺寸,进行布局,然后将渲染树绘制到屏幕上。
    • 事件监听与用户交互:直到页面变得可交互,浏览器开始监听用户的动作,如点击、滚动等。
  7. 浏览器在页面加载完成后或不需要和服务器通信时,可以主动关闭 TCP 连接,或者等待服务器的关闭请求。
  8. 后续操作:浏览器可能继续监听用户事件,执行异步JS代码,处理AJAX请求等。

URL的组成

URL(Uniform Resource Locators),即统一资源定位器。网络上的所有资源都靠 URL 来定位,每一个文件就对应着一个 URL,就像是路径地址。

URL的组成

  • 协议:用于指定访问资源的协议,如 http、https、ftp(文件传输)、file(本地文件)、mailto(邮件)、telnet(远程登录)等。
  • 域名/IP:用于指定资源所在的主机名或 IP 地址。
  • 端口号:用于指定访问资源的端口号,HTTP默认端口号是 80,HTTPS默认端口号是 443。
  • 资源路径:从第一个/开始,表示从服务器上根目录开始进行索引到的文件路径。
  • 参数:浏览器在向服务器提交请求时,在 URL 中附带着参数会提取这些参数。参数采用键值对的形式key=value,每一个键值对使用&隔开。
  • 锚点:锚点就是在要访问的页面上的一个锚点,可以直接跳转到指定的位置。在 URL 中,锚点以#开头,并且不会作为请求的一部分发送给服务端。

DNS域名系统

DNS(Domain Name System)域名管理系统,是当用户使用浏览器访问网址之后,使用的第一个重要协议,解决的是域名和 IP 地址的映射问题。

DNS解析过程

浏览器在本地维护一个hosts列表,用户访问网址时,先查看要访问的域名是否在hosts列表中,如果有就直接提取对应的 IP 地址记录,如果没有就使用 DNS 服务器获取域名和 IP 地址的映射。

DNS服务器
DNS 服务器自底向上几个层级:

  • 根域名服务器:负责管理顶级域名服务器的 IP 地址。世界上有 600多个根服务器,但只有 13 个 IP 地址。为了提高 DNS 的可靠性、安全性和性能,每个IP地址对应多个服务器。
  • 顶级域 DNS 服务器(TLD 服务器):负责管理各个顶级域名服务器的 IP 地址。如 .com.cn.org.net 等。
  • 权威 DNS 服务器:在因特网上具有公共可访问主机的每个组织机构必须提供公共可访问的 DNS 记录,如baidu.com 的 DNS 服务器,负责管理该域名下的所有子域名。
  • 本地 DNS 服务器:每个 ISP(互联网服务提供商)都有一个自己的本地 DNS 服务器。

DNS工作流程
主机cis.poly.edu想知道gaia.cs.umass.edu的 IP 地址。
迭代式查询
递归式查询

HTTP状态码

状态码 类别 原因短语
1XX Informational(信息性状态码) 接收的请求正在处理
2XX Success(成功状态码) 请求正常处理完毕
3XX Redirection(重定向状态码) 需要进行附加操作以完成请求
4XX Client Error(客户端错误状态码) 服务器无法处理请求
5XX Server Error(服务器错误状态码) 服务器处理请求出错
  • 200 OK:请求被成功处理。如发送查询用户数据的 HTTP 请求到服务端,服务端正确返回了用户数据。

  • 201 Created:请求被成功处理并且在服务端创建了一个新的资源。如通过 POST 请求创建一个新的用户。

  • 202 Accepted:服务端已接收到了请求,但还未处理。

  • 204 No Content:服务端已经成功处理了请求,但是没有返回任何内容。

  • 206 Partial Content:服务端成功处理了部分请求。如请求一个大文件,服务端只返回了部分内容。

  • 301 Moved Permanently:资源被永久重定向了。如网站的网址更换了。

  • 302 Found:资源被临时重定向了。如网站暂时关闭,重定向到一个临时的页面。

  • 304 Not Modified:客户端发送了一个条件式请求,服务端告诉客户端资源未被修改,可以使用缓存的资源。

  • 400 Bad Request:发送的 HTTP 请求存在问题。如请求参数不合法、请求方法错误。

  • 401 Unauthorized:未认证却请求需要认证之后才能访问的资源。

  • 403 Forbidden:直接拒绝 HTTP 请求,不处理。一般用来针对非法请求。

  • 404 Not Found:请求的资源未在服务端找到。如请求某个用户的信息,服务端并没有找到指定的用户。

  • 409 Conflict:表示请求的资源与服务端当前的状态存在冲突,请求无法被处理。

  • 500 Internal Server Error:服务端出问题了(通常是服务端出 Bug 了)。如服务端处理请求的时候突然抛出异常,但异常并未在服务端被正确处理。

  • 502 Bad Gateway:网关将请求转发到服务端,但服务端返回的却是一个错误的响应。

HTTP/HTTPS区别

基本概念

  • HTTP协议:用来规范超文本的传输,主要用来是规范浏览器和服务器端的行为。扩展性强、速度快、跨平台支持性好。
  • HTTPS协议:HTTPS基于HTTP协议,并使用 SSL/TLS 协议用作加密和安全认证,其更安全可靠。保密性好、信任度高。

HTTP和HTTPS协议都需要三次握手建立连接、四次挥手断开连接。

HTTP和HTTPS的区别

  • HTTP是明文传输,HTTPS使用SSL进行加密加密传输,更安全可靠。
  • HTTP默认端口是80,HTTPS默认端口是443。
  • HTTP连接简单,无状态,HTTPS握手阶段比较费时,所以HTTP比HTTPS快。

HTTP通信过程
HTTP 是应用层协议,它以 TCP(传输层)作为底层协议,通信过程主要如下:

  • 服务器在 80 端口等待客户的请求。
  • 浏览器发起到服务器的 TCP 连接(创建套接字 Socket)。
  • 服务器接收来自浏览器的 TCP 连接。
  • 浏览器(HTTP 客户端)与 Web 服务器(HTTP 服务器)交换 HTTP 消息。
  • 关闭 TCP 连接。

SSL/TSL协议加密原理

HTTPS 协议中,SSL 通道通常使用基于密钥的加密算法,密钥长度通常是 40 比特或 128 比特。

SSL/TLS 的加密的原理是非对称加密和对称加密的配合使用。对称加密用来加密数据,并生成唯一私有密钥 k,非对称加密用来加密k。通信双方(Client、Server)只需要一次非对称加密,交换对称加密的密钥k,在之后的信息通信中,使用绝对安全的密钥k,对信息进行对称加密,即可保证传输消息的保密性。

  • 非对称加密采用两个密钥:公钥、私钥。在通信时,私钥仅由Server保存,公钥由Client所知晓。公钥用于加密数据,私钥用于解密数据。
  • 对称加密中双方共享唯一密钥 k,加解密算法已知,加密方利用密钥 k 加密,解密方利用密钥 k 解密。

公钥传输隐患
假设存在攻击者 A,其对应服务器为AServer,A发送给Client一个假包,假装是Server公钥,其实是诱饵服务器 AServer的公钥,Client收到后误以为是 Server的公钥,Client后续使用AServer公钥加密密钥k,然后在公开信道传输,那么攻击者 A可以捕获加密的包,然后用AServer的私钥解密,得到密钥k,这样攻击者 A 就可以解密Client和Server之间的通信。

数字证书
为了解决这个问题,需要使用数字证书,数字证书是由权威机构(CA,Certificate Authority)颁发的,用于证明公钥的合法性。具体流程如下:
假设有服务器 Server,CA 机构,客户端 Client。

  1. Server信任 CA,CA也知道 Server公钥,CA首先为 Server颁发证书(包含 Server公钥),采用散列技术为证书生成一个摘要,然后使用 CA私钥对摘要进行加密,生成数字签名。
  2. Server获得 CA颁发的证书和数字签名,并在 Client请求时,将证书和数字签名一并发送给 Client。
  3. Client信任 CA并知晓 CA公钥。Client在收到 Server的证书和数字签名时,使用 CA公钥解密数字签名,得到摘要,然后使用相同的散列技术为证书生成摘要。
  4. Client对比两个摘要是否一致,如果一致则证明证书(包含 Server公钥)是真实的,可以使用 Server公钥加密密钥k,然后在公开信道传输。

HTTP无状态如何保存用户状态

可以使用 Session 机制来保存用户状态。服务端给特定的用户创建特定的 Session 之后就可以标识这个用户并且跟踪这个用户了(一般情况下,服务器会在一定时间内保存这个 Session,过了时间限制,就会销毁这个 Session)。

服务端可以使用内存和数据库保存Session,Session 跟踪是通过在客户端的 Cookie 中存放 Session ID 来实现的。如果 Cookie被禁用可以利用 URL 重写把 Session ID 直接附加在 URL 路径的后面。

URI/URL区别

  • URI(Uniform Resource Identifier)是统一资源标志符,可以唯一标识一个资源。
  • URL(Uniform Resource Locator)是统一资源定位符,可以提供该资源的路径。它是一种具体的 URI,即 URL 可以用来标识一个资源,而且还指明了如何 定位 这个资源。

URI 的作用像身份证号一样,URL 的作用更像家庭住址一样。URL 是一种具体的 URI,它不仅唯一标识资源,而且还提供了定位该资源的信息。

Session/Cookie区别

  • 存储位置不同:Cookie 存储在客户端,Session 存储在服务端。
  • 存储容量不同:单个Cookie保存的数据<=4KB,一个站点最多保存20个Cookie。Session 存储在服务端,一般没有存储容量限制,但考虑服务器性能,一般会设置 Session 的有效期和存储容量。
  • 安全性不同:Cookie 存储在客户端,容易被篡改,不安全。Session 存储在服务端,相对安全。
  • 生命周期不同:Cookie 有过期时间,可以设置长期有效的 Cookie。Session 一般保存在内存中,会话结束后会被销毁。
  • 作用范围不同:Cookie 的作用范围是整个域名,Session 的作用范围是当前会话。
  • 传输方式不同:Cookie 会随着 HTTP 请求一起发送到服务端,Session 保存在服务端,客户端只会收到 Session ID。

GET/POST区别

  • GET 用于获取或查询资源,POST 用于创建或修改资源。
  • GET 请求是幂等的,即多次重复执行不会改变资源的状态,POST 请求是不幂等的,即每次执行可能会产生不同的结果或影响资源的状态。
  • GET 请求参数会附加在 URL 后面,POST 请求参数会放在请求体(body)中。
  • GET 请求的URL长度受到浏览器和服务器的限制,POST 请求的 body大小则没有明确的限制。
  • 由于 GET 请求是幂等的,可以被缓存,而POST 请求是不幂等的,不适合被缓存。
  • GET 请求的安全性较差,参数会暴露在 URL 中,POST 请求的安全性较好,参数在请求体中,不会暴露在 URL 中。

幂等:一个操作、方法或函数被调用多次,其结果与仅调用一次相同。

WebSocket

WebSocket 是一种基于 TCP 连接的全双工通信协议,即客户端和服务器可以同时发送和接收数据。

WebSocket 协议是应用层的协议,用于弥补 HTTP 协议在持久通信能力上的不足。客户端和服务器仅需一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

WebSocket 的常见应用场景:视频弹幕、实时消息推送、实时游戏对战、多用户协同编辑、社交聊天等。

WebSocket/HTTP区别

  • WebSocket 是全双工通信,HTTP 是单向通信。且 HTTP 协议只能由客户端发起,服务器只能响应请求。
  • WebSocket 是持久连接,HTTP 是短连接。HTTP 请求结束后,连接就会断开,而 WebSocket 连接会一直保持。
  • WebSocket 使用 ws://wss://作为协议前缀,HTTP 使用 http://https://作为协议前缀。
  • WebSocket 通信数据格式比较轻量,用于协议控制的数据包头部相对较小,而 HTTP 通信每次都要携带完整的头部,网络开销较大。
  • WebSocket 支持扩展,可以自定义协议,HTTP 不支持扩展。

WebSocket工作流程

  1. 客户端向服务器发起一个 HTTP 请求,请求头中包含 Upgrade: websocketSec-WebSocket-Key等字段,表示要求升级协议为 WebSocket。
  2. 服务器收到请求后,会进行协议升级,如果支持 WebSocket 协议,将回复HTTP 101状态码,响应头中包含Upgrade: websocketSec-WebSocket-Accept:xxx等字段,表示升级成功。
  3. 现在已经建立了 WebSocket 连接,可以进行双向的数据传输。连接建立之后,通过心跳机制保持连接的稳定性和活跃性。数据以帧(frames)的形式传输,WebSocket的发送端将每条消息被切分成多个帧发送,接收端将关联的帧重新组装成完整的消息。
  4. 关闭连接时,双方都可以发送一个关闭帧,表示关闭连接。另一方收到后,会回复一个关闭帧,然后关闭连接。

PING命令原理

PING 命令是一种常用的网络诊断工具,经常用来测试网络中主机之间的连通性和网络延迟。

1
2
3
4
5
6
7
8
9
10
ping -c 4 www.baidu.com
PING www.baidu.com(36.155.132.3): 56 data bytes
64 bytes from 36.155.132.3: icmp_seq=0 ttl=49 time=8.890 ms
64 bytes from 36.155.132.3: icmp_seq=1 ttl=49 time=8.874 ms
64 bytes from 36.155.132.3: icmp_seq=2 ttl=49 time=9.136 ms
64 bytes from 36.155.132.3: icmp_seq=3 ttl=49 time=9.400 ms

--- www.baidu.com ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 8.874/9.075/9.400/0.214 ms

输出由以下几部分组成:

  • ICMP Echo Request(请求报文)信息:序列号、TTL(Time to Live)值。
  • 目标主机的域名或 IP 地址:输出结果的第一行。
  • 往返时间(RTT,Round-Trip Time):从发送 ICMP Echo Request(请求报文)到接收到 ICMP Echo Reply(响应报文)的总时间,用来衡量网络连接的延迟。
  • 统计结果(Statistics):包括发送的 ICMP 请求数据包数量、接收到的 ICMP 响应数据包数量、丢包率、往返时间(RTT)的最小、平均、最大和标准偏差值。

如果PING目标主机无法正确响应,则说明网络连通性出现问题。

PING命令的原理是基于 ICMP 协议,通过发送 ICMP Echo Request(请求报文)到目标主机,目标主机收到请求后,会返回 ICMP Echo Reply(响应报文)给发送方,从而实现网络连通性的测试。

HTTP/TCP区别

  • TCP 是一种底层的传输协议,提供可靠的数据传输。
  • HTTP 是一种应用层协议,使用 TCP 作为其传输层协议,专门用于 web 数据的传输。
  1. 层次:TCP 位于传输层,HTTP 位于应用层。
  2. 功能:TCP 提供可靠的、面向连接的通信。HTTP 用于在客户端和服务器之间传输超文本数据(如 HTML 文档、图片、视频等)。
  3. 连接方式:TCP 通过三次握手建立连接,确保通信双方准备就绪。HTTP 基于请求-响应模型,客户端发送请求,服务器返回响应。
  4. 数据传输:TCP 是流式传输数据,没有消息边界。HTTP 是面向消息,每个请求和响应都是独立的。
  5. 错误检测和恢复:TCP 具有错误检测和恢复机制,保证数据完整性。HTTP 没有错误检测和恢复机制,需要依赖 TCP 来保证数据传输的可靠性。且 HTTP 无状态,依赖于 Cookie 和 Session 来保存用户状态。
  6. 用途:TCP 适用于需要高可靠性的数据传输,如文件传输、电子邮件等。HTTP 主要用于万维网(WWW)上的数据通信,如浏览网页、提交表单等。

HTTP 是建立在 TCP 之上的,它利用 TCP 提供的可靠连接来传输数据,但它们在网络模型中的层次和具体功能上有所不同。

TCP、UDP区别

二者都是常见的传输层协议。

  • TCP(Transmission Control Protocol,传输控制协议 ):提供 面向连接 的,可靠 的数据传输服务。
  • UDP(User Datagram Protocol,用户数据协议):提供 无连接 的,尽最大努力 的数据传输服务(不保证数据传输的可靠性),简单高效。

区别总结:

  1. TCP面向连接(三次握手四次挥手),UDP是无连接的,即发送数据之前不需要建立连接
  2. TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
  3. TCP面向字节流,TCP把数据看成一连串无结构的字节流,UDP是面向报文的,UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如实时视频会议)
  4. TCP只支持点对点通信,UDP支持一对一,一对多,多对一和多对多的交互通信
  5. TCP首部开销20字节,UDP的首部开销小,只有8个字节
  6. TCP通信信道是全双工的可靠信道,UDP则是不可靠信道

原文链接:https://blog.csdn.net/Li_Ning_/article/details/52117463

TCP/UDP应用场景

https://blog.csdn.net/qq_44273429/article/details/131375961

由于TCP提供了可靠的、有序的数据传输,它适用于以下场景:

  • 文件传输:TCP的可靠性和有序性确保了文件在传输过程中不会丢失和损坏,并按正确的顺序接收。
  • 网页浏览:TCP可靠地传输网页内容,确保网页的准确显示。
  • 电子邮件传输:TCP保证电子邮件的传输不会出现丢失或乱序的情况。
  • 远程登录:TCP提供了稳定的连接,适合远程登录操作。
  • 数据库管理系统:TCP确保了数据库的一致性和完整性,防止数据丢失和损坏。

由于UDP具有低延迟和高效性的特点,它适用于以下场景:

  • 视频流和音频流传输:由于UDP的低延迟,它常用于视频流和音频流的实时传输,如在线直播、视频会议等。
  • 实时游戏:UDP的快速传输和低延迟使其成为在线游戏中常用的协议,可以实现实时的游戏数据传输。
  • DNS(域名系统):UDP广泛用于域名系统中,用于域名解析和查询。
  • 实时传感器数据:UDP适用于需要快速传输实时传感器数据的场景,如工业自动化、物联网等

UDP的广播和多播

  • UDP广播是指将数据包发送到同一子网内的所有设备。广播消息使用了一个特殊的IP地址,该地址的子网内主机标志部分的二进制全部为1(即点分十进制IP的最后一部分是255)。例如,在子网192.168.1.x中,广播地址是192.168.1.255。
    • 特点:
      • 广播消息可以被子网内的所有设备接收,无需设备事先注册或加入特定的组。
      • 广播只能在局域网内使用,广域网中无法使用UDP进行广播。
      • 广播的开销较小,因为发送者只需发送一个数据包,而该数据包会被子网内的所有设备接收。
    • 应用场景:
      • 局域网内的通知或广播消息,如DHCP(动态主机配置协议)服务器向局域网内的设备发送IP地址分配信息。
      • 局域网内的设备发现或同步操作,如打印机共享或文件同步服务。
  • UDP多播(也称为组播)是一种将数据包发送到一组特定接收者的网络通信模式。多播使用特定的多播地址(在IPv4中为224.0.0.0到239.255.255.255范围内的地址),该地址标识了一组接收数据的接口。
    • 特点:
      • 多播比广播具有更高的可控性,只有加入多播组的接收者才能接收数据。
      • 多播不仅限于局域网,也可以用于广域网环境,适用于在大型网络中分发数据。
      • 多播地址由IANA(互联网号码分配机构)进行全球分配和管理。
    • 应用场景:
      • 视频直播:将视频数据同时分发给大量观众。
      • 文件分发:向大量客户端分发相同文件。
      • 在线游戏:实现游戏房间的快速组建和对手匹配。
      • 监控系统:将视频数据同时分发给多个监控终端。
      • 分布式计算:将计算任务分发给多个节点。

多播工作工程:

  1. 发送者创建一个UDP套接字,并设置多播属性。
  2. 发送者使用sendto()函数向多播地址发送数据。
  3. 网络设备(如路由器)根据多播路由协议(如IGMP、PIM等)将数据包转发到需要接收该数据的各个网段。
  4. 接收者通过加入多播组来接收数据,使用setsockopt()函数设置套接字加入多播组。

如何将UDP变为将TCP那样可靠

要使 UDP 像 TCP 那样可靠,需要在应用层实现类似 TCP 的功能。以下是一些常见的方法和步骤:

  1. 数据包确认机制(ACK):每当接收方收到一个数据包时,它会发送一个确认(ACK)回给发送方。发送方在发送数据包后会等待 ACK,如果在一定时间内没有收到 ACK,则会重传该数据包。
  2. 序列号:在每个数据包中添加一个序列号,以便接收方可以按顺序重组数据包,并检测丢失或重复的数据包。
  3. 超时和重传:发送方在发送每个数据包后启动一个定时器。如果在规定时间内没有收到 ACK,则会重传该数据包。
  4. 滑动窗口:使用滑动窗口协议来控制数据包的流动。发送方可以在等待 ACK 的同时继续发送多个数据包,从而提高传输效率。
  5. 校验和:在数据包中包含校验和,以检测数据包在传输过程中是否被损坏。接收方会检查校验和,并丢弃任何损坏的数据包。
  6. 流量控制:发送方和接收方协商一个窗口大小,以确保发送方不会超过接收方的处理能力。

三次握手四次挥手✅

建立 TCP 连接需要“三次握手”,缺一不可:

  • 一次握手:客户端发送带有 SYN(SEQ=x)标志的数据包 -> 服务端,然后客户端进入 SYN_SEND 状态,等待服务端的确认;
  • 二次握手:服务端发送带有 SYN+ACK(SEQ=y,ACK=x+1)标志的数据包 –> 客户端,然后服务端进入 SYN_RECV 状态;
  • 三次握手:客户端发送带有 ACK(ACK=y+1)标志的数据包 –> 服务端,然后客户端和服务端都进入ESTABLISHED状态,完成 TCP 三次握手。

注意,连接建立后,客户端和服务端都可以发送数据。

断开 TCP 连接则需要“四次挥手”,缺一不可:

  • 第一次挥手:客户端发送一个 FIN(SEQ=x)标志的数据包 -> 服务端,用来关闭客户端到服务端的数据传送。然后客户端进入 FIN-WAIT-1 状态。
  • 第二次挥手:服务端收到FIN标志的数据包,它发送一个 ACK(ACK=x+1)标志的数据包 -> 客户端。然后服务端进入 CLOSE-WAIT 状态,客户端进入 FIN-WAIT-2状态。
  • 第三次挥手:服务端发送一个 FIN(SEQ=y)标志的数据包 -> 客户端,请求关闭连接,然后服务端进入 LAST-ACK 状态。
  • 第四次挥手:客户端发送 ACK(ACK=y+1)标志的数据包 -> 服务端,然后客户端进入TIME-WAIT状态,服务端在收到 ACK(ACK=y+1)标志的数据包后进入 CLOSE 状态。此时如果客户端等待 2MSL 后依然没有收到回复,就证明服务端已正常关闭,随后客户端也可以关闭连接了。

TCP 是全双工通信,可以双向传输数据。任何一方都可以在数据传送结束后发出连接释放的通知,待对方确认后进入半关闭状态。当另一方也没有数据再发送的时候,则发出连接释放通知,对方确认后就完全关闭了 TCP 连接。

只要四次挥手没有结束,客户端和服务端就可以继续传输数据!

2MSL, Maximum Segment Lifetime,即最长报文段寿命的两倍。

三次握手

四次挥手

TIME_WAIT/CLOSE_WAIT是什么

TIME_WAIT/CLOSE_WAIT是TCP关闭连接过程中出现的两种状态。

  • CLOSE_WAIT是被动关闭连接的一方(通常是服务器)出现的一种状态,当TCP连接的一端(被动关闭方)收到对方发送的FIN报文时,会发送一个ACK报文作为响应,并进入CLOSE_WAIT状态。
  • TIME_WAIT是主动关闭连接的一方(通常是客户端)出现的一种状态,当主动关闭连接的一方收到对方发送的FIN报文并发送自己的ACK报文后,就会进入TIME_WAIT状态。这个状态会持续2MSL(两倍的报文最大生存时间)。

半连接队列/全连接队列

在三次握手中,Linux 内核会维护两个队列管理连接请求:

  • 半连接队列(也称 SYN Queue):当服务端收到客户端的 SYN 请求时,此时双方还没有完全建立连接,服务端会把半连接状态的连接放在半连接队列。
  • 全连接队列(也称 Accept Queue):当服务端收到客户端的 ACK 请求时,意味着三次握手成功完成,服务端会将该连接从半连接队列移动到全连接队列。若未收到 ACK 请求,会进行重传,若超过最大重传次数,系统将从半连接队列中删除该连接信息。

两队列的存在是为了处理并发请求,确保服务端能够有效地管理新的连接请求。

为什么要三次握手

三次握手为的是确认双方收发功能都正常,缺一不可。

  • 第一次握手:Client 无法确认任何信息;Server 确认了:对方发送正常,自己接收正常
  • 第二次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:对方发送正常,自己接收正常
  • 第三次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己发送、接收正常,对方发送、接收正常

第二次握手为何传回ACK和SYN

为什么传回ACK
第二次握手中,服务端传回 ACK 是为了确认接收到客户端的 SYN 报文。
为什么传回SYN
在第一次握手中,客户端发送 SYN包 是为了建立客户端到服务端的连接,然而 TCP 连接是双向的,服务端到客户端也需要建立连接,所以服务端在第二次握手中向客户端发送 SYN包,以建立服务端到客户端的连接。

同时发送 SYN 包和 ACK包,服务器能够在一个报文中同时完成这两个操作,从而减少报文的数量,加快连接建立的效率。

三次握手中可以携带数据吗

允许在第三次发送 ACK 的时候携带数据,但是不建议这样做,因为在第三次握手时,服务端还没有确认客户端的 ACK 包,可能会导致数据丢失。

为什么要四次挥手

  • 确保数据传输的完整性和可靠性:在任何一方关闭连接之前,确保所有数据都已正确接收和处理。
  • 保证双向关闭的确认:TCP 是全双工通信,每一方都需要确认对方的关闭请求,以避免数据丢失和连接的不正常终止。
  • 避免半开连接:确保在关闭过程中,没有未完成的数据传输或者遗留的数据包。
  • 保证连接的有序终止:TCP 是全双工的,每一方都需要单独关闭自己的发送和接收通道,因此需要四步来完成这一过程。

四次挥手虽然复杂,但却能够确保连接的稳定、可靠和有序终止。

为何不能把服务端发送的ACK和FIN合并变成三次挥手

因为服务端收到客户端断开连接的请求时,可能还有一些数据没有发完,这时先回复 ACK,表示接收到了断开连接的请求。等到数据发完之后再发 FIN,断开服务端到客户端的数据传送。

如果第二次挥手客户端未收到服务端发送的ACK会怎样

客户端没有收到 ACK 确认,会重新发送 FIN 请求。

为什么第四次握手客户端需等待2*MSL

第四次挥手时,客户端发送服务端的 ACK 有可能丢失,如果服务端没收到 ACK 的话,服务端就会重发 FIN,如果客户端在 2*MSL 的时间内收到了 FIN,就会重新发送 ACK 并再次等待 2MSL,防止 Server 没有收到 ACK 而不断重发 FIN

MSL(Maximum Segment Lifetime): 一个片段在网络中最大的存活时间,2MSL 就是一个发送和一个回复所需的最大时间。如果直到 2MSL,Client 都没有再次收到 FIN,那么 Client 推断 ACK 已经被成功接收,则结束 TCP 连接。

TCP如何保证连接可靠性

  1. 基于数据块传输:数据被分割成 TCP 认为最适合发送的数据块,再传输给网络层,数据块被称为报文段或段。
  2. 对失序数据包重新排序以及去重:TCP 为了保证不发生丢包,给每个包一个序列号,这使得能够将接收到的数据根据序列号排序,去掉重复序列号的数据就可以实现数据包去重。
  3. 校验和:TCP 有端到端的校验和机制,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃此报文段和不确认收到此报文段。
  4. 重传机制:在数据包丢失或延迟的情况下,重新发送数据包,直到收到对方的确认应答(ACK)。
    • 超时重传:当发送方发送数据后,如果超时重传计时器超时,仍没有收到接收方的确认应答,就会重传数据包。
    • 快速重传:当发送方连续收到三个重复的 ACK 时,立即重传相应的数据包,而不必等待超时。
  5. TCP 连接每一方都有固定大小的缓冲空间,TCP 的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP 利用滑动窗口实现流量控制。
  6. 拥塞控制:当网络拥塞时,减少数据的发送。TCP 在发送数据的时候会考虑网络的拥塞程度,由拥塞窗口表示,它是发送方根据网络状况自己维护的一个值,表示发送方认为可以在网络中传输的数据量。发送方发送数据的大小是滑动窗口和拥塞窗口的最小值,这样可以保证发送方既不会超过接收方的接收能力,也不会造成网络的过度拥塞。

如何实现快速重传

快速重传(Fast Retransmit):当发送方连续收到三个重复的ACK时,立即重传相应的数据包,而不必等待超时。

  • 快速重传就是要发送方尽快重传,而不是等待超时重传计时器超时再重传。
    • 要求接收方不要等待自己发送数据时捎带ACK,而是立即发送ACK
    • 即使收到了失序的报文段,也要立即发送对自己收到的报文段的重复确认ACK
    • 发送方一旦收到三个连续的ACK,就立即重传对应的报文段,而不必等待超时重传计时器超时。
    • 使用快速重传可以将网络吞吐量提高 20%~30%。

TCP如何实现流量控制

TCP 利用滑动窗口实现流量控制。流量控制是为了控制发送方发送速率,保证接收方来得及接收。 接收方发送的确认报文中的窗口字段用来控制发送方窗口大小,从而影响发送方的发送速率。将窗口字段设置为 0,则发送方不能发送数据。

为什么需要流量控制

因为双方在通信的时候,发送方的速率与接收方的速率是不一定相等,如果发送方的发送速率太快,会导致接收方处理不过来。如果处理不过来,会先将数据放入接收缓冲区(Receiving Buffers)里。如果接收缓冲区满了,就只能把再收到的数据包丢掉。而丢包会浪费网络资源。因此要让接收方与发送方处于一种动态平衡。

为什么要进行拥塞控制

拥塞控制是为了避免网络拥塞,确保网络的稳定性和可靠性。当网络中的数据包过多,超过网络的处理能力时,就会发生拥塞,导致数据包丢失、延迟增加、吞吐量下降等问题。拥塞控制的目的是通过限制发送方的发送速率,避免过多的数据包注入到网络中,从而保持网络的正常运行。

TCP拥塞控制的四种算法

https://blog.csdn.net/love_668/article/details/116913790

  • 慢开始(Slow Start):初始阶段发送方以指数增长的方式增加拥塞窗口(Congestion Window, cwnd),逐渐探测网络的可用带宽。
  • 拥塞避免(Congestion Avoidance):当cwnd达到慢启动阈值(Slow Start Threshold, ssthresh)时,cwnd以线性增长方式增加。
    • 发送方维护一个拥塞窗口(cwnd),用于控制发送数据的速率,其值取决于网络的拥塞程度,并且动态变化。
      • cwnd的维护原则:只要网络没有拥塞,就增大cwnd,以提高发送速率;一旦网络出现拥塞,就减小cwnd
      • 判断拥塞依据:没有按时收到应当到达的报文(即发生超时重传)。
    • 发送方将拥塞窗口作为发送窗口swnd,即swnd=cwnd
    • 维护一个慢开始门限ssthresh状态变量:
      • cwnd < ssthresh时,使用慢开始算法;
      • cwnd > ssthresh时,停止使用慢开始算法而改用拥塞避免算法;
      • cwnd = ssthresh时,既可以使用慢开始算法,也可以使用拥塞避免算法;
    • 在TCP双方建立逻辑连接关系时,cwnd的值被设置为1,慢开始门限ssthresh值进行设置(假设为 16)。
    1. 慢开始阶段:cwnd从1开始,每收到一个ACKcwnd加倍,即cwnd = cwnd * 2,直到cwnd >= ssthresh
    2. cwnd >= ssthresh,开始执行拥塞避免算法,cwnd每次只增加1,即cwnd = cwnd + 1
    3. 如果此时部分数据报文段丢失,那么发送方会对这些丢失的数据报文段进行超时重传。发送方以此判断可能发生了网络拥塞,进行调整:将慢开始门限值ssthresh值更新为发生拥塞时cwnd值的一半;将cwnd的值减少为1,并重新开始执行慢开始算法。
    4. cwnd重新达到新的ssthresh时,再次执行拥塞避免算法。
  • 快速重传(Fast Retransmit):当发送方连续收到三个重复的ACK时,立即重传相应的数据包,而不必等待超时。
  • 快速恢复(Fast Recovery):在快速重传后,cwnd减半,但不重新进入慢启动,而是进入快速恢复阶段,通过继续发送数据来尽快恢复网络的正常传输。
    • 有时候个别报文丢失,但实际上并没有网络拥塞。这导致发送发超时重传,误认为发生了网络拥塞,错误地使用慢开始算法,降低了网络的传输效率。为了解决这个问题,TCP引入了快速重传机制、快速恢复机制。
    • 快速重传就是要发送方尽快重传,而不是等待超时重传计时器超时再重传。
      • 要求接收方不要等待自己发送数据时捎带ACK,而是立即发送ACK
      • 即使收到了失序的报文段,也要立即发送对自己收到的报文段的重复确认ACK
      • 发送方一旦收到三个连续的ACK,就立即重传对应的报文段,而不必等待超时重传计时器超时。
      • 使用快速重传可以将网络吞吐量提高 20%~30%。
    • 发送方收到三个重复的ACK,就知道只是丢失了个别报文,所以不使用慢开始算法,而是使用快恢复算法。
      • 发送方将慢开始门限ssthresh和拥塞窗口cwnd设置为原来cwnd的一半,然后执行拥塞避免算法。
      • 有的快恢复算法实现是将新的拥塞窗口设置的大一点,即cwnd = ssthresh(cwnd/2) + 3,然后执行拥塞避免算法。

TCP拥塞控制

注意:
慢开始是指一开始向网络中注入的报文少,并不是指cwnd的增长速度慢;
拥塞避免并非不能完全避免拥塞,而是在网络出现拥塞时使用线性增长方式控制cwnd,使网络不容易出现拥塞。

TCP如何实现拥塞控制

TCP 发送发维持一个 拥塞窗口(cwnd)的状态变量。采用了四种算法,即 慢开始拥塞避免快重传快恢复

  • 发送方维护一个拥塞窗口(cwnd),用于控制发送数据的速率,其值取决于网络的拥塞程度,并且动态变化。
    • cwnd的维护原则:只要网络没有拥塞,就增大cwnd,以提高发送速率;一旦网络出现拥塞,就减小cwnd
    • 判断拥塞依据:没有按时收到应当到达的报文(即发生超时重传)。
  • 发送方将拥塞窗口作为发送窗口swnd,即swnd=cwnd
  • 维护一个慢开始门限ssthresh状态变量:
    • cwnd < ssthresh时,使用慢开始算法;
    • cwnd > ssthresh时,停止使用慢开始算法而改用拥塞避免算法;
    • cwnd = ssthresh时,既可以使用慢开始算法,也可以使用拥塞避免算法;
  • 在TCP双方建立逻辑连接关系时,cwnd的值被设置为1,慢开始门限ssthresh值进行设置(假设为 16)。
  1. 慢开始阶段:cwnd从1开始,每收到一个ACKcwnd加倍,即cwnd = cwnd * 2,直到cwnd >= ssthresh
  2. cwnd >= ssthresh,开始执行拥塞避免算法,cwnd每次只增加1,即cwnd = cwnd + 1
  3. 如果此时部分数据报文段丢失,那么发送方会对这些丢失的数据报文段进行超时重传。发送方以此判断可能发生了网络拥塞,进行调整:将慢开始门限值ssthresh值更新为发生拥塞时cwnd值的一半;将cwnd的值减少为1,并重新开始执行慢开始算法。
  4. cwnd重新达到新的ssthresh时,再次执行拥塞避免算法。
  • 有时候个别报文丢失,但实际上并没有网络拥塞。这导致发送发超时重传,误认为发生了网络拥塞,错误地使用慢开始算法,降低了网络的传输效率。为了解决这个问题,TCP引入了快速重传机制、快速恢复机制。
  • 快速重传就是要发送方尽快重传,而不是等待超时重传计时器超时再重传。
    • 要求接收方不要等待自己发送数据时捎带ACK,而是立即发送ACK
    • 即使收到了失序的报文段,也要立即发送对自己收到的报文段的重复确认ACK
    • 发送方一旦收到三个连续的ACK,就立即重传对应的报文段,而不必等待超时重传计时器超时。
    • 使用快速重传可以将网络吞吐量提高 20%~30%。
  • 发送方收到三个重复的ACK,就知道只是丢失了个别报文,所以不使用慢开始算法,而是使用快恢复算法。
    • 发送方将慢开始门限ssthresh和拥塞窗口cwnd设置为原来cwnd的一半,然后执行拥塞避免算法。
    • 有的快恢复算法实现是将新的拥塞窗口设置的大一点,即cwnd = ssthresh(cwnd/2) + 3,然后执行拥塞避免算法。

TCP解决丢包问题

  • 重传机制
    • 超时重传(Retransmission TimeOut, RTO):当发送方没有在预期时间内收到确认应答(ACK)时,认为数据包丢失,重新发送该数据包。
    • 快速重传(Fast Retransmit):当发送方连续收到三个重复的ACK时,立即重传相应的数据包,而不必等待超时。
  • 拥塞控制
    • 慢启动(Slow Start):初始阶段发送方以指数增长的方式增加拥塞窗口(Congestion Window, CWND),逐渐探测网络的可用带宽。
    • 拥塞避免(Congestion Avoidance):当CWND达到慢启动阈值(Slow Start Threshold, SSTHRESH)时,CWND以线性增长方式增加。
    • 快速恢复(Fast Recovery):在快速重传后,CWND减半,但不重新进入慢启动,而是进入快速恢复阶段,通过继续发送数据来尽快恢复网络的正常传输。
    • 快速重传(Fast Retransmit):当发送方连续收到三个重复的ACK时,立即重传相应的数据包,而不必等待超时。
  • 选择性确认(Selective Acknowledgement, SACK):允许接收方通知发送方已接收的非连续数据块,发送方可以只重传丢失的部分数据,而不是所有后续数据包。
  • 冗余传输(Redundant Transmission):使用前向纠错码(Forward Error Correction, FEC)或者额外的冗余数据,以便在接收方能够自行修复部分丢失的数据包。
  • 流量控制(Flow Control):通过调整接收窗口(Receiver Window, RWND)的大小,确保发送方不会发送超过接收方处理能力的数据量,减少因拥塞而导致的丢包。
  • 网络层优化
    • 质量服务(Quality of Service, QoS):在路由器和交换机上设置优先级规则,确保关键数据包优先传输。
    • 负载均衡(Load Balancing):将流量分布到多个路径或链路上,避免某一路径过载导致丢包。
  • 物理层优化:改善物理连接质量,如使用更好的网络电缆、优化无线信号强度等,以减少物理层的丢包率。
  • 网络协议的改进:Quick UDP Internet Connections(QUIC),谷歌开发的一种基于UDP的协议,具有更快速的连接建立和恢复能力。

通过结合以上各种方法,可以更有效地应对TCP丢包问题,提高网络传输的稳定性和效率。

TCP粘包拆包问题

https://blog.csdn.net/u010429831/article/details/119932832
TCP 是一个面向字节流的传输层协议。发送方无法保证对方每次收到的都是一个完整的数据包。于是就有了粘包、拆包问题的出现。粘包、拆包问题只发生在TCP协议中。

  • 接收端只收到一个TCP报文段,去掉首部后,报文段中包含发送端发送来的两个数据包的信息,即为粘包。由于接收端不知道两数据包的界限,所以对于接收端来说很难处理。
  • 接收端收到了两个TCP报文段,但是去掉首部后,两个数据包要么是不完整的,要么就是多出来一部分,这种现象即为粘包、拆包问题。
    • 粘包问题分两种:一种是粘在一起的包都是完整的数据包,另一种情况是粘在一起的包有不完整的数据包。
    • 拆包:应用程序的数据包被拆分成若干部分发送出去,从接收缓存看,接收方收到的只是数据包的一部分内容。

粘包产生原因

  • 应用程序(发送方)进程写入的数据量大于TCP发送缓冲区的大小,这将会发生拆包。此时数据包需要进行拆包处理,分多次进行发送。
  • 应用进程写入的数据量小于TCP发送缓冲区的大小,这将会发生粘包。由于TCP发送缓存空间足够,它会等到有多个数据包时,再组装成一个TCP报文段,然后通过网卡发送到网络中去。
  • 当应用进程发送的数据包大于 MSS(最大报文段长度: TCP报文段的长度 - TCP首部长度)时,将会发生拆包。TCP 协议会将大的数据包拆分成 MSS 大小的数据包进行发送。
  • 接收方不及时读取接收缓冲区中的数据,将会发生粘包。接收方先把接收到的数据存放在内核接收缓冲区中,用户进程从接收缓冲区读取数据,若下一个数据包到达时前一个数据包尚未被用户进程取走,则下一个数据包放到内核接收缓冲区时就和前一数据包粘在一起,而用户进程根据预先设定的缓冲区大小从内核接收缓冲区读取数据,这样就一次性读取到了多个数据包。

什么时候需要考虑粘包问题
TCP是长连接,并且传输的是结构化数据时,如:传送的是一个结构体类型的数据,由于不知道结构化数据的边界,容易导致粘包问题的出现。这时需要考虑粘包问题的影响。

什么时候不需要考虑粘包问题

  • 如果 TCP 是短连接,即只进行一次数据通信过程,通信完成就关闭连接,这样就不会出现粘包问题。
  • 如果传输的是字符串、文件等无结构化数据时,也不会出现粘包问题。因为发送方只管发送,接收方只管接收存储就行了

粘包问题解决方案

  1. 发送定长包。即发送端将每个数据包封装为固定长度(长度不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。(适合定长结构的数据)
  2. 包头加上包体长度。发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便可以知道每一个数据包的实际长度了。(适合不定长结构的数据)
  3. 在包尾部设置边界标记。发送端在每个数据包尾部添加边界标记,可以使用特殊符号作为边界标记。如此,接收端通过这个边界标记就可以将不同的数据包拆分开来。但这可能会存在一个问题:如果数据包内容中也包含有边界标记,则会被误判为消息的边界,导致出错。这样方法要视具体情况而定。例如,FTP协议就是采用 “\r\n” 来识别一个消息的边界的。

ARQ协议

自动重传请求(Automatic Repeat-reQuest,ARQ)是数据链路层和传输层的错误纠正协议之一。它通过使用确认和超时这两个机制,在不可靠服务的基础上实现可靠的信息传输。如果发送方在发送后一段时间之内没有收到确认信息ACK,就会重新发送,直到收到确认或者重试超过一定的次数。

停止等待ARQ协议

停止等待协议是为了实现可靠传输的,它的基本原理就是每发完一个分组就停止发送,等待对方确认(回复 ACK)。如果过了一段时间(超时时间后),还是没有收到 ACK 确认,说明没有发送成功,需要重新发送,直到收到确认后再发下一个分组;

连续ARQ协议

连续 ARQ 协议可提高信道利用率。发送方维持一个发送窗口,凡位于发送窗口内的分组可以连续发送出去,而不需要等待对方确认。接收方一般采用累计确认,对按序到达的最后一个分组发送确认,表明到这个分组为止的所有分组都已经正确收到了。

  • 优点:信道利用率高,容易实现。
  • 缺点:不能向发送方反映出接收方已经正确收到的所有分组的信息。如:发送方发送了5条消息,中间第三条丢失(3号),这时接收方只能对前两个发送确认。发送方无法知道后三个分组的下落,而只好把后三个全部重传一次。这也叫 Go-Back-N(回退 N),表示需要退回来重传已经发送过的 N 个消息。

超时重传机制如何实现

发送方发送完数据后,会启动一个定时器,等待接收端确认收到这个报文段。接收端成功收到报文段的话会发送会 ACK包,如果发送端在合理的往返时延(RTT)内未收到确认信息,那数据包就被标记为已丢失并进行重传。

超时重传时间 RTO(Retransmission Time Out)直接影响到 TCP 的性能和效率。如果 RTO 设置得太小,会导致不必要的重传,增加网络负担;如果 RTO 设置得太大,会导致数据传输的延迟,降低吞吐量。因此 RTO 应根据网络的实际状况,动态地进行调整。

超时重传时间不能直接使用往返时延RTT,因为其值会随着网络波动而变化。

IP地址

IP地址是每个连入互联网的设备或域(如计算机、服务器、路由器等)都被分配的一个唯一标识符。

IP地址过滤

IP 地址过滤(IP Address Filtering)就是限制或阻止特定 IP 地址或 IP 地址范围的访问。如:有一个图片服务突然被某一个 IP 地址攻击,那就可以禁止这个 IP 地址访问图片服务。

IPv4/IPv6区别

IPv4(Internet Protocol version 4)是四组由点分隔的数字,例如:123.89.46.72。IPv4 使用 4Bytes 32 位(bits)地址作为其 Internet 地址,共有约 42 亿(2^32)个可用 IP 地址。不够用。

为了解决 IP 地址耗尽的问题,采用具有更大地址空间的新版本 IP 协议 - IPv6(Internet Protocol version 6)。该格式使用由单或双冒号分隔的一组数字和字母,如:2001:0db8:85a3:0000:0000:8a2e:0370:7334。IPv6 使用 128 位互联网地址,有 2^128个可用 IP 地址。

  • IPv4采用DHCP(动态主机配置协议)来自动分配IP地址。IPv6支持自动配置(SLAAC)和DHCPv6,自动化程度更高。
  • IPv4路由表较大,互联网的快速增长导致路由表膨胀,路由效率受到一定影响。IPv6有更高效的路由聚合(aggregation),路由表规模更小,有助于提高路由效率。

断点续传在浏览器如何实现

断点续传是一种在网络传输中恢复中断数据的技术,常用于下载文件时继续未完成的部分。浏览器中实现断点续传主要依赖HTTP的Range头和状态码206 Partial Content

  • Range头:客户端在请求资源时,通过Range头指定请求的范围,如Range: bytes=500-表示请求资源的 500 字节之后的部分。
  • 206 Partial Content:服务器收到带有Range头的请求后,会返回状态码206 Partial Content,并在响应头中包含Content-Range字段,指示返回的数据范围。
  • 实现细节:
    1. 发送初始请求:浏览器首先发送一个普通的GET请求,下载文件的起始部分。
    2. 检测中断:如果下载中断或用户暂停下载,记录下已下载的字节数。
    3. 发送带Range头的请求:重新开始下载时,浏览器发送一个带有Range头的请求,从上次中断的地方继续。
    4. 处理服务器响应:服务器返回206 Partial Content状态码和请求范围的内容,浏览器继续下载剩余部分。

如何判断浏览器是否支持断点续传
要检测浏览器是否支持断点续传,可以通过发送一个带有Range头的请求,并检查服务器的响应。如果服务器返回状态码206 Partial Content,则表示支持断点续传。

处理不支持断点续传的情况
如果浏览器或服务器不支持断点续传,可以采取以下几种策略:

  • 完整下载:直接进行完整下载,而不是尝试断点续传。
  • 分块下载:将文件分成多个小块,分别下载并在客户端合并。这种方法需要服务器支持多部分下载,但不依赖于HTTP的断点续传功能。

在项目中处理断点续传的支持性
在实际项目中,通常会有以下步骤来处理断点续传的支持性:

  • 检测支持性:如上所示,首先检测浏览器是否支持断点续传。
  • 优先使用断点续传:如果支持,使用断点续传来提高下载效率和用户体验。
  • 回退方案:如果不支持,使用完整下载或其他替代方案。
  • 用户提示:在用户界面上显示相关提示,例如告诉用户当前浏览器不支持断点续传,可能需要更长时间下载。

操作系统

用户态和内核态

  • 用户态是指应用程序运行时所处的模式。在用户态下,程序执行受到严格的限制,不能直接访问硬件或内存中的关键部分。任何试图进行这些操作的指令都会导致异常,并且操作系统会终止该程序。这种限制可以防止用户程序破坏系统的稳定性和安全性。
    • 受限的指令集:只能执行非特权指令。
    • 受限的资源访问:不能直接访问硬件设备和内核内存空间。
    • 需要通过系统调用(System Call)与内核进行交互。
  • 内核态是指操作系统内核运行时所处的模式。在内核态下,系统具有完全的访问权限,可以执行任何指令,并且可以访问所有的硬件设备和内存。这种模式下,操作系统能够管理系统资源和控制硬件。
    • 完全的指令集:可以执行所有的指令,包括特权指令。
    • 完全的资源访问:可以直接访问硬件设备和内存。
    • 执行关键任务:处理系统调用、中断处理、设备管理等。

切换

  • 系统调用:当用户态的应用程序需要执行特权操作(如读写文件、分配内存、访问硬件设备)时,它会发出一个系统调用请求,触发从用户态到内核态的切换。内核处理完系统调用后,会返回用户态继续执行应用程序。
  • 中断:当外围设备完成用户请求的操作后,会向 CPU 发出相应的中断信号,这时 CPU 会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序。这种从用户态到内核态的切换是由硬件中断控制器完成的。
  • 异常:当 CPU 在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。

示例

  • 用户态:运行中的应用程序,如文本编辑器、浏览器等。它们通过系统调用请求操作系统提供的服务。
  • 内核态:操作系统内核在处理系统调用、硬件中断或其他低级别任务时的运行状态。

安全性和稳定性
用户态和内核态的分离是现代操作系统安全性和稳定性的关键。通过将用户程序与操作系统核心隔离,防止用户程序直接操作硬件或内存,减少了系统崩溃和安全漏洞的风险。

总结
用户态和内核态的划分使得计算机系统能够有效地管理资源,提供安全的运行环境,同时允许用户程序执行。用户态用于执行普通应用程序,而内核态用于执行操作系统核心任务,保证了系统的稳定性和安全性。

只有内核态不行吗?

  • 在 CPU 的所有指令中,有一些指令是比较危险的比如内存分配、设置时钟、IO 处理等,如果所有的程序都能使用这些指令的话,会对系统的正常运行造成灾难性地影响。因此,需要限制这些危险指令只能内核态运行。这些只能由操作系统内核态执行的指令也被叫做 特权指令 。
  • 如果计算机系统中只有一个内核态,那么所有程序或进程都必须共享系统资源,例如内存、CPU、硬盘等,这将导致系统资源的竞争和冲突,从而影响系统性能和效率。并且,这样也会让系统的安全性降低,毕竟所有程序或进程都具有相同的特权级别和访问权限。

系统调用

系统调用是应用程序与操作系统之间进行交互的一种方式,通过系统调用,应用程序可以访问操作系统底层资源例如文件、设备、网络等。

系统调用(System Call)是操作系统提供给应用程序的接口,用于访问操作系统内核的服务和功能。在用户程序中,凡是与系统态级别的资源有关的操作(如文件管理、进程控制、内存管理等),必须通过系统调用方式向操作系统提出服务请求,并由操作系统代为完成。

系统调用分下面几类:

  • 设备管理:完成设备(输入输出设备和外部存储设备等)的请求或释放,以及设备启动等功能。
  • 文件管理:完成文件的读、写、创建及删除等功能。
  • 进程管理:进程的创建、撤销、阻塞、唤醒,进程间的通信等功能。
  • 内存管理:完成内存的分配、回收以及获取作业占用内存区大小及地址等功能。

系统调用和普通库函数调用非常相似,只是系统调用由操作系统内核提供,运行于内核态,而普通的库函数调用由函数库或用户自己提供,运行于用户态。

虚拟内存

虚拟内存是一种内存管理技术,它为每个进程提供了一个统一的地址空间,使得进程认为它独占一个大的连续内存空间。然而,实际的物理内存可能是零散的或不足的,操作系统通过虚拟内存技术将虚拟地址转换为物理地址,从而透明地管理内存。

主要作用:

  • 隔离进程:物理内存通过虚拟地址空间访问,虚拟地址空间与进程一一对应。每个进程都认为自己拥有了整个物理内存,进程之间彼此隔离,一个进程中的代码无法更改正在由另一进程或操作系统使用的物理内存。
  • 提升物理内存利用率:有了虚拟地址空间后,操作系统只需要将进程当前正在使用的部分数据或指令加载入物理内存。
  • 简化内存管理:进程都有一个一致且私有的虚拟地址空间,程序员不用和真正的物理内存打交道,而是借助虚拟地址空间访问物理内存,从而简化了内存管理。
  • 多个进程共享物理内存:进程在运行过程中,会加载许多操作系统的动态库。这些库对于每个进程而言都是公用的,它们在内存中实际只会加载一份,这部分称为共享内存。
  • 提高内存使用安全性:控制进程对物理内存的访问,隔离不同进程的访问权限,提高系统的安全性。
  • 提供更大的可使用内存空间:可以让程序拥有超过系统物理内存大小的可用内存空间。这是因为当物理内存不够用时,可以利用磁盘充当,将物理内存页(通常大小为 4 KB)保存到磁盘文件(会影响读写速度),数据或代码页会根据需要在物理内存与磁盘之间移动。

没有虚拟内存会存在什么问题?

  • 程序之间的内存隔离性差:没有虚拟内存,不同程序的内存空间可能会重叠,一个程序可以访问另一个程序的内存空间,导致数据泄露或者程序崩溃。
  • 物理内存利用率低:没有虚拟内存,每个程序都需要占用一定的物理内存,如果物理内存不足,就会导致程序无法运行。
  • 程序的内存管理复杂:没有虚拟内存,程序需要直接管理物理内存,需要考虑内存的分配、释放、回收等问题,增加了程序的复杂性。
  • 程序的安全性差:没有虚拟内存,程序可以直接访问物理内存,可能会导致程序的安全漏洞,如缓冲区溢出等。

内存池

内存池(Memory Pool)是一种内存管理技术,旨在提高内存分配和释放的效率,同时减少内存碎片化的问题。内存池主要用于那些需要频繁进行内存分配和释放的场景,比如游戏开发、实时系统、嵌入式系统等。

内存池可以在应用程序级别实现,也可以在操作系统内核中实现。例如,操作系统内核中的一些子系统(如文件系统、网络堆栈等)可能会使用内存池来提高内存管理的效率。在用户态,应用程序可以自行实现内存池,或者使用一些第三方库来管理内存池。而在内核态,操作系统可能会提供类似的机制来优化内存管理。

内存碎片

  • 外部碎片化(External Fragmentation):内存中存在许多小的、非连续的空闲块,导致大块内存请求无法满足,即使总的空闲内存量足够。
  • 内部碎片化(Internal Fragmentation):分配的内存块内部有未被使用的空间,因为分配的块大于实际需要的内存。

内存池如何解决内存碎片问题

  • 预先分配固定大小的内存块:内存池通常在初始化时预先分配一大块连续的内存,然后将这块内存划分成许多大小相等的内存块。这样做可以避免外部碎片化,因为所有的内存分配都是从预先划分好的内存块中进行的。
  • 减少分配和释放次数:通过预先分配和重用内存块,内存池减少了系统进行内存分配和释放的次数。这不仅提高了性能,还减少了产生碎片的机会。
  • 分层内存池:有些内存池会根据不同大小的内存请求划分成多个子池,每个子池管理一种特定大小的内存块。这样可以有效减少内部碎片化,因为每个内存块的大小都是根据需求精细划分的。

进程/线程/协程

https://blog.csdn.net/m0_60505735/article/details/131047046
https://blog.csdn.net/weixin_49199646/article/details/109210547

  • 进程: 进程是程序的一次执行过程,是系统资源分配和运行程序的基本单位;一个进程在其执行的过程中可以产生多个线程。
  • 线程: 线程是进程的一个执行单元,是任务调度和系统执行的最小单位;与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈。所以系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
  • 协程: 协程是一种用户态的轻量级线程,协程的调度完全由用户控制。

进程与线程的区别

  • 根本区别: 进程是操作系统资源分配和独立运行的最小单位;线程是任务调度和系统执行的最小单位。
  • 地址空间区别: 每个进程都有独立的地址空间,一个进程崩溃不影响其它进程;一个进程中的多个线程共享该 进程的地址空间,一个线程的非法操作会使整个进程崩溃。
  • 上下文切换开销区别: 每个进程有独立的代码和数据空间,进程之间上下文切换开销较大;线程组共享代码和数据空间,线程之间切换的开销较小。

进程与线程的联系
一个进程由共享空间(包括堆、代码区、数据区、进程空间和打开的文件描述符)和一个或多个线程组成,各个线程之间共享进程的内存空间。而一个标准的线程由线程ID、程序计数器PC、寄存器和栈组成。

进程与线程的选择

  • 线程的创建或销毁的代价比进程小,需要频繁创建和销毁时应优先选用线程;
  • 线程上下文切换的速度比进程快,需要大量计算时优先选用线程;
  • 线程在CPU上的使用效率更高,需要多核分布时优先选用线程,需要多机分布时优先选用进程
  • 线程的安全性、稳定性没有进程好,需要更稳定安全时优先使用进程。

综上,线程创建和销毁的代价低、上下文切换速度快、对系统资源占用小、对CPU的使用效率高,因此一般情况下优先选择线程进行高并发编程;但线程组的所有线程共用一个进程的内存空间,安全稳定性相对较差,若其中一个线程发生崩溃,可能会使整个进程,因此对安全稳定性要求较高时,需要优先选择进程进行高并发编程。

进程间的通信方式

进程间通信(Inter-Process Communication, IPC)是指在操作系统中不同进程之间传递数据或信息的机制。常见的进程间通信方式有多种,每种方式都有其独特的应用场景和优缺点。以下是一些主要的进程间通信方式:

  1. 管道(Pipes):
    • 匿名管道(Anonymous Pipes):主要用于有亲缘关系的进程之间的通信,如父子进程。数据以字节流的形式在进程间传递。
    • 命名管道(Named Pipes):支持在无亲缘关系的进程之间进行通信。命名管道存在于文件系统中,可以被不同的进程打开和使用。
  2. 消息队列(Message Queues):
    • 允许进程通过发送和接收消息进行通信。消息队列提供了一种在进程间传递数据的有序方式,可以实现异步通信。
  3. 共享内存(Shared Memory):
    • 进程共享一段内存空间,进程可以直接读写这段共享内存中的数据。共享内存是最快的一种通信方式,因为数据不需要在进程间复制,但需要额外的同步机制来避免并发访问问题。
  4. 信号量(Semaphores):
    • 用于控制多个进程对共享资源的访问,通过信号量可以实现进程间的同步和互斥。
  5. 信号(Signals):
    • 信号是一种有限的异步通知机制,用于通知进程某个事件的发生。进程可以捕捉和处理信号,从而实现简单的通信和控制。
  6. 套接字(Sockets):
    • 套接字不仅支持同一台计算机上进程间的通信,也支持分布式网络中不同计算机上的进程间通信。常用于网络编程中。
  7. 文件系统(File System):
    • 进程可以通过读写共享的文件进行通信。这种方式简单但效率较低,适用于需要持久化存储的场景。
  8. 内存映射文件(Memory-Mapped Files):
    • 通过将文件映射到进程的地址空间,实现文件内容的共享和通信。与共享内存类似,但数据的持久化由文件系统提供。

线程间的通信方式

线程间的通信是指在同一个进程内,不同线程之间交换数据或信号的机制。常见的线程间通信方式包括以下几种:

  1. 共享内存:
    • 全局变量:所有线程都可以访问和修改同一个全局变量。
    • 静态变量:静态变量在进程的生命周期内只初始化一次,所有线程共享。
  2. 互斥锁(Mutex):
    • 用于防止多个线程同时访问共享资源,从而避免数据竞争。
  3. 读写锁(RWLock):
    • 允许多个线程同时读数据,但在写数据时需要独占锁,确保写操作的安全性。
  4. 信号量(Semaphore):
    • 主要用于限制对共享资源的访问数量,可以控制同时访问资源的线程数。
  5. 条件变量(Condition Variable):
    • 用于线程之间的等待通知机制,一个线程可以等待一个条件变量,而另一个线程可以通知该条件变量改变状态,从而唤醒等待的线程。
  6. 事件(Event):
    • 线程可以等待一个事件,直到另一个线程设置该事件,从而实现线程之间的同步。
  7. 队列(Queue):
    • 线程安全的队列,常用于生产者-消费者模型,一个线程放入数据,另一个线程取出数据。
  8. 管道(Pipe):
    • 用于线程之间的数据传输,常见于一些操作系统提供的进程间通信机制中。
  9. 消息队列(Message Queue):
    • 一种线程安全的队列,专门用于在多个线程之间传递消息。
  10. 信号(Signal):
  • 一种用于通知线程某个事件发生的机制,通常用在异步事件处理。

CPU满载如何排查问题

当CPU满载时,排查问题通常需要系统地检查多个方面,以确定导致高负载的具体原因。以下是一些详细的排查步骤:

  1. 使用系统监控工具
    查看系统负载:首先,使用系统监控工具(如Windows的任务管理器、Linux的top或htop命令)来查看系统的整体负载情况,包括CPU、内存、磁盘和网络等资源的使用情况。
    确定高占用进程:在监控工具中查找哪个进程或应用程序的CPU占用率很高。这通常是导致CPU满载的直接原因。
  2. 分析进程和资源使用情况
    查看进程详细信息:在任务管理器或相应的系统监控工具中,查看高占用进程的详细信息,包括其启动时间、占用资源量、关联的模块或服务等。
    检查进程行为:分析进程的行为,看是否有异常操作或不必要的资源占用。例如,某些进程可能因为死循环、内存泄漏或低效的算法而持续占用大量CPU资源。
  3. 检查系统配置和设置
    查看启动项和服务:检查系统启动时自动运行的程序和服务,看是否有不必要的程序或服务在后台运行并占用CPU资源。
    优化系统设置:关闭不必要的后台程序、禁用不必要的系统服务、降低屏幕分辨率或减少同时打开的窗口数量等,以降低CPU的使用率。
  4. 检查硬件和驱动程序
    检查硬件状态:确保CPU、内存、硬盘等硬件设备工作正常,没有过热、损坏或性能瓶颈等问题。
    更新驱动程序:确保所有硬件设备的驱动程序都是最新的,以避免因驱动程序问题导致的CPU高占用。
  5. 排查病毒和恶意软件
    运行杀毒软件:使用可靠的杀毒软件对系统进行全面扫描,以排除病毒或恶意软件导致的CPU高占用。
    检查系统日志:查看系统日志文件,查找是否有与病毒或恶意软件相关的异常记录。
  6. 使用性能分析工具
    使用专业工具:对于复杂的问题,可以使用专业的性能分析工具(如VisualVM、Arthas等)来进一步分析CPU使用情况,并确定具体的性能瓶颈。
  7. 咨询专业人员
    如果以上步骤都无法解决问题,或者您对系统配置和性能分析不熟悉,建议咨询专业的技术人员或计算机维修人员。
    通过以上步骤,您可以系统地排查CPU满载的问题,并找到导致高负载的具体原因。在排查过程中,请保持耐心和细心,以便准确地定位问题并采取相应的解决措施。

孤儿进程

在操作系统中,孤儿进程(Orphan Process)和僵尸进程(Zombie Process)是两种特殊的进程状态,它们各自具有特定的行为和影响。

孤儿进程(Orphan Process)定义:孤儿进程是指在其父进程执行完毕或被终止后,该进程仍然运行着的进程。这些进程会被操作系统中的“进程收养所”(通常是init进程,其PID为1)收养,成为init进程的子进程。

特点:

  • 孤儿进程不再是任何有效进程的子进程。
  • 孤儿进程的结束处理由收养它的进程(如init进程)负责。
  • 孤儿进程本身对系统没有直接的负面影响,因为操作系统能够正确处理它们。

孤儿进程是系统能够自动处理的,

僵尸进程

僵尸进程(Zombie Process)定义:僵尸进程是指已经结束(即已经完成了执行)但是其父进程尚未通过调用wait()或waitpid()等系统调用来获取其终止状态的进程。

特点:

  • 僵尸进程已经释放了除进程描述符以外的所有资源,但仍在进程表中占有一个表项,这意味着它们的PID仍然被占用。
  • 如果系统中有大量僵尸进程,可能会导致PID耗尽,从而影响新进程的创建。
  • 僵尸进程的存在是为了让父进程能够查询子进程的退出状态。如果父进程不调用wait()或waitpid(),子进程就会一直处于僵尸状态。

解决方法:

  • 确保父进程在适当的时候调用wait()或waitpid()来回收子进程的终止状态,从而避免僵尸进程的产生。
  • 如果父进程已经结束,而子进程成为僵尸进程,那么这些僵尸进程最终会被init进程收养,并由init进程调用wait()来回收。
  • 在某些情况下,如果父进程确实不需要知道子进程的退出状态,可以考虑在子进程中调用_exit()而不是exit(),这样可以在子进程结束时立即释放资源,但这种方法并不推荐,因为它可能掩盖了潜在的错误。

僵尸进程则需要程序员通过编程来避免其产生或及时回收。

动态链接和静态链接的区别

动态链接和静态链接是计算机科学中两种重要的程序链接方式。

  • 静态链接:在程序编译时,将所有外部库文件(如DLL文件在Windows系统中,或.so文件在Linux系统中)直接嵌入到可执行文件中,形成一个独立的可执行文件。当程序运行时,就不需要再加载这些外部库文件。
  • 动态链接:在程序编译时,只生成程序的可执行文件和一些必要的资源文件,而将外部库文件放在一个单独的目录下(如系统的PATH环境变量所指定的目录)。当程序运行时,系统会在这些目录下查找所需的外部库文件,并将其加载到内存中。

优缺点
静态链接

  • 优点:

    • 程序运行时不依赖于外部库文件,减少了程序的依赖性,提高了程序的独立性和安全性。
    • 避免了因外部库文件版本不匹配导致的兼容性问题。
    • 在某些情况下,可以提高程序的运行速度(尽管这取决于具体情况,如硬盘读写速度等)。
  • 缺点:

    • 程序体积较大,因为包含了所有外部库文件的代码。
    • 升级程序时需要替换所有的外部库文件,增加了维护成本。
    • 灵活性较差,无法实现模块化编程。
      动态链接
  • 优点:

    • 程序体积较小,因为不包含外部库文件的代码,只包含对外部库文件的引用。
    • 便于升级和维护,只需替换外部库文件即可,无需重新编译整个程序。
    • 灵活性高,可以根据需要加载不同的库或模块,实现模块化编程。
    • 节省内存和磁盘空间,因为多个程序可以共享同一个外部库文件。
  • 缺点:

    • 程序运行时需要依赖于外部库文件,可能导致安全性问题和兼容性问题。
    • 性能开销较大,因为程序运行时需要不断地检查外部库或模块是否已经加载。
    • 可能导致内存泄漏等问题,需要开发者更加关注内存管理。
  • 应用场景

    • 静态链接:适用于需要将程序打包成一个独立的可执行文件,并且不需要频繁更新外部库文件的场景。例如,嵌入式系统、游戏等对性能和安全性要求较高的应用程序。
    • 动态链接:适用于项目规模较大、模块化程度较高的项目,以及需要频繁更新外部库文件的场景。例如,操作系统、数据库等需要不断更新的软件。

Linux

常见Linux线程间的通信方式

如何查询内存大小

1
2
3
4
# -h选项表示以人类可读的格式(如KB、MB、GB)显示内存大小。
free -h
# /proc/meminfo文件包含了详细的内存使用信息。可以在这个文件中搜索与内存大小相关的信息,比如MemTotal项显示了总的物理内存大小。
cat /proc/meminfo

如何查询系统日志文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 对于使用systemd的Linux系统,journalctl命令是查看系统日志的强大工具。
# 查看所有系统日志
journalctl
# 查看nginx服务器的日志
journalctl -u nginx.service
# 查看系统启动时的日志
journalctl -b
# 查看系统上一次启动时的日志
journalctl -b -1
# 搜索包含特定文本的日志
journalctl | grep "特定文本"
# 对于不直接使用systemd日志或需要查看传统日志文件的情况,可以直接查看/var/log目录下的日志文件。
# 查看系统消息日志(通常是系统级别的警告和错误信息):
cat /var/log/syslog
# 或者在某些系统中可能是
cat /var/log/messages
# 查看认证和授权相关的日志(如SSH登录尝试):
cat /var/log/auth.log
# 或者
cat /var/log/secure
# 查看Web服务器(如Apache或Nginx)的日志(通常位于/var/log/apache2或/var/log/nginx目录):
cat /var/log/apache2/access.log
cat /var/log/nginx/access.log

使用logrotate管理日志文件。/var/log目录下的日志文件可能会随着时间增长而变得非常大。为了管理这些日志文件的大小和数量,大多数Linux系统使用logrotate工具定期轮转、压缩、删除或邮寄旧日志文件。logrotate的配置文件通常位于/etc/logrotate.conf以及/etc/logrotate.d/目录下的文件中。

管道

管道(Pipes)使用竖线|)符号表示。它的作用是将一个命令的输出作为另一个命令的输入。这样,用户可以将多个命令串联起来,形成一个命令管道,从而执行复杂的任务。

1
2
# 查找当前目录下所有.txt文件,并显示这些文件的内容行数:
ls *.txt | xargs wc -l

这里,ls *.txt命令列出所有.txt文件,然后通过管道|将这些文件名传递给xargs命令,xargs命令再将这些文件名作为wc -l命令的参数,wc -l命令计算并显示每个文件的行数。

重定向

重定向(Redirection)允许用户将命令的输出(标准输出或标准错误输出)重定向到文件或其他命令中,或者将文件的内容作为命令的输入。重定向使用大于号(>)和小于号(<)等符号表示。

  • 标准输出重定向(>):将命令的输出重定向到文件中。如果文件已存在,则覆盖原有内容;如果文件不存在,则创建新文件。
  • 标准输出追加重定向(>>):将命令的输出追加到文件的末尾,而不是覆盖原有内容。
  • 标准输入重定向(<):将文件的内容作为命令的输入。
  • 标准错误输出重定向(2>):将命令的错误输出重定向到文件中。
    1
    2
    3
    4
    5
    6
    7
    8
    # 将ls命令的输出(即当前目录下的文件和目录列表)重定向到files.txt文件中。
    ls > files.txt
    # 将文本"Hello, World!"追加到greeting.txt文件的末尾。
    echo "Hello, World!" >> greeting.txt
    # 将files.txt文件的内容作为wc -l命令的输入,计算并显示文件的行数。
    wc -l < files.txt
    # 如果non_existent_file文件不存在,ls命令的错误输出(通常是“No such file or directory”消息)将被重定向到errors.txt文件中。
    ls non_existent_file 2> errors.txt

Linux如何查看文件前5行

1
head -n 5 filename

Linux怎么看进程占用多少内存

在Linux系统中,查看进程占用多少内存可以通过多种方法实现。以下是一些常用的方法和命令:

  1. 使用top命令
    top命令是Linux系统中一个实时监控系统资源使用情况的工具,包括CPU、内存等。通过top命令,你可以看到系统中各个进程的内存占用情况。

运行top命令后,你可以看到类似以下的输出(输出内容会根据实际系统情况有所不同):
top - 11:15:16 up 1 day, 1:23, 2 users, load average: 0.00, 0.01, 0.05
Tasks: 123 total, 1 running, 122 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.3 us, 0.7 sy, 0.0 ni, 98.7 id, 0.0 wa, 0.0 hi, 0.3 si, 0.0 st
MiB Mem : 7815.1 total, 1234.1 free, 2345.6 used, 4235.4 buff/cache
MiB Swap: 2048.0 total, 2048.0 free, 0.0 used. 4977.8 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1234 user1 20 0 1024m 200m 50m S 0.0 2.6 0:01.23 myprocess
在上面的输出中,%MEM列表示进程占用的内存比例,RES列表示进程实际使用的物理内存大小(以KB或MB为单位,具体取决于你的系统配置和top命令的显示设置)。

  1. 使用ps命令
    ps命令用于显示当前进程的快照。结合适当的选项,你可以查看进程的内存使用情况。

例如,使用ps aux –sort=-%mem命令可以按照内存使用率从高到低的顺序列出所有进程及其内存使用情况:
bash
ps aux –sort=-%mem
输出将包含进程的PID、用户、CPU和内存使用率等信息。

  1. 使用grep和/proc文件系统
    每个Linux进程都有一个对应的/proc/[pid]/status文件,其中包含了该进程的状态信息,包括内存使用情况。

你可以使用grep命令从该文件中提取特定的内存信息,如VmRSS(表示进程实际占用的物理内存大小):
bash
grep VmRSS /proc/1234/status
将1234替换为你想要查看的进程PID。

  1. 使用高级工具
    除了上述基本命令外,还有一些高级工具可以帮助你更详细地分析进程的内存使用情况,如htop、atop、smem等。

htop是top命令的增强版本,提供了更丰富的信息和更友好的用户界面。
atop是一个性能监控工具,可以显示系统资源(包括内存)的综合使用情况。
smem是一个用于统计进程和用户内存使用的命令行工具,它可以提供更详细的内存统计信息。
这些工具通常不是Linux系统的默认安装部分,但你可以通过包管理器(如apt、yum等)轻松安装它们。

总之,Linux提供了多种方法来查看进程的内存占用情况,你可以根据自己的需求和喜好选择合适的方法。

Linux抓包

Linux抓包是Linux系统下进行网络流量分析、故障诊断和安全审计等任务的重要手段。以下是对Linux抓包的详细介绍:

  • tcpdump
    功能:tcpdump是一个强大的命令行抓包工具,可以捕获经过网络接口的数据包,并将其显示或保存到文件中。它支持复杂的过滤器和表达式,能够灵活地筛选和捕获所需的数据包。
    特点:tcpdump是Linux系统自带的抓包工具之一,使用起来非常方便。它提供了丰富的选项和参数,可以精确控制抓包过程,包括指定网络接口、设置抓包数量、保存抓包数据等。
    使用场景:适用于需要深入分析网络流量、诊断网络问题或进行安全审计的场景。
1
tcpdump [ -adeflnNOpqStvx ] [ -c 数量 ] [ -F 文件名 ] [ -i 网络接口 ] [ -r 文件名] [ -s snaplen ] [ -T 类型 ] [ -w 文件名] [表达式 ]

二、常用选项说明
-a:将网络地址和广播地址转变成名字。
-c 数量:指定要抓取的包的数量。
-d:将匹配信息包的代码以人们能够理解的汇编格式给出。
-e:在输出行打印出数据链路层的头部信息,例如源MAC和目标MAC。
-f:将外部的Internet地址以数字的形式打印出来。
-i 网络接口:指定tcpdump需要监听的接口。
-n:对地址以数字方式显式,不进行主机名解析。
-nn:除了-n的作用外,还把端口显示为数值,不进行端口名解析。
-P:指定要抓取的包是流入还是流出的包,可以给定的值为”in”、”out”和”inout”,默认为”inout”。
-q:快速打印输出,即打印很少的协议相关信息,输出行简短。
-s snaplen:设置tcpdump的数据包抓取长度为snaplen,如果不设置默认将会是65535字节。
-t:在输出的每一行不打印时间戳。
-v、-vv、-vvv:分别产生详细程度递增的输出信息。
-w 文件名:将抓包数据输出到文件中而不是标准输出。
-r 文件名:从给定的数据包文件中读取数据。
-X:输出包的头部数据,以16进制和ASCII两种方式同时输出。
-XX:输出包的头部数据,以16进制和ASCII两种方式同时输出,更详细。
-D:列出可用于抓包的接口。
-F:从文件中读取抓包的表达式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 默认启动
tcpdump
# 默认情况下,tcpdump将监视第一个网络接口(非lo口)上所有流通的数据包。
# 监视指定网络接口的数据包
tcpdump -i eth1
# 如果不指定网卡,默认tcpdump只会监视第一个网络接口,如eth0。
# 截获主机hostname发送的所有数据
tcpdump src host hostname
# 监视所有发送到主机hostname的数据包
tcpdump dst host hostname
# 监视指定主机和端口的数据包
tcpdump tcp port 22 and host hostname
# 抓取包含特定IP的数据包
tcpdump -i eth0 -vnn host 10.84.10.217
# 抓取包含特定端口的数据包
tcpdump -i eth0 -vnn port 22
# 抓取特定协议的数据包
tcpdump -i eth0 -vnn udp
# 将抓取的数据包记录存到文件中
tcpdump -i eth0 -vnn -w /tmp/fil1 -c 100
# 从文件中读取数据包进行分析
tcpdump -i eth0 -vnn -r /tmp/fil1 tcp

tcpdump只能抓取流经本机的数据包。
在使用复杂的表达式时,建议使用单引号将表达式括起来,以防止shell对特殊字符进行错误解析。抓取长度(snaplen)的设置需要根据实际需求进行调整,以避免包截断或处理时间过长。