初识网络原理概念
IP地址和端口号
IP地址用于定位主机的网络地址。
IP 地址(IPv4 地址)由 32 位正整数来表示,IP 地址在计算机是以二进制的方式处理的。
人们为了方便记忆采用了点分十进制的标记方式,也就是将 32 位 IP 地址以每 8 位为组,共分为 4
组,每组以「 . 」隔开,再将每组转换成十进制。
端口号用于定位主机中的进程
端口号是0~65535范围的数字,在网络通信中,进程可以通过绑定一个端口号,来发送及接收网络数
据。
注意:两个不同的进程,不能绑定同一个端口号,但一个进程可以绑定多个端口号
计算机网络层次总体架构
开放式系统互联模型(Open System Interconnection Model,缩写:OSI;简称为OSI模型)
TCP/IP五层(或四层)模型
TCP/IP通讯协议采用了5层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。
应用层 | 负责应用层序间的沟通 |
---|---|
传输层 | 负责两台主机之间的数据传输 |
网络层 | 负责地址管理和路由选择 |
数据链路层 | 负责设备之间的数据帧的传送和识别 |
物理层 | 负责光/电信号的传递方式 |
应用层协议之HTTP
HTTP基本概念
HTTP(超文本传输协议)是一种应用非常广泛的应用层协议。
HTTP往往是基于传输层的TCP协议实现的(HTTP1.0,HTTP1.1,HTTP2.0均为TCP,HTTP基于UDP实现)
详细解释「超文本传输协议」?
从协议的角度理解HTTP:HTTP 是一个用在计算机世界里的协议。它使用计算机能够理理解的语言确立了一种计算机之间交流通信的规范(两个以上的参与者),以及相关的各种控制和错误处理方(行为约定和规范)。
从传输的角度理解HTTP:HTTP 协议是一个双向协议。在 HTTP 里,需要中间人遵从 HTTP 协议,只要不打扰基本的数据传输,就可以添加任意额外的东西。
从超文本的角度理解HTTP:HTTP 传输的内容是「超文本」。
总结:HTTP 是一个在计算机世界里专门在「两点」之间「传输」文字、图片、音频、视频等「超文本」数据的「约定和规范」。
HTTP 常见的状态码,有哪些?
常见的HTTP状态码:表示这次请求的“结果”
- 200OK:表示访问成功
- 301 Moved Permanently:永久重定向(永久重定向,旧地址被永久移除,客户端向新地址发送请求。)
- 302 Move temporarily:临时重定向(临时重定向,旧地址还在,客户端继续向旧地址发送请求。)
- 400 Bad Request :表示客户端请求的报文有错误,但只是个笼统的错误。
- 403 Forbidden:访问被拒绝(例如没有权限或者没有登录)
- 404 Not Found:没有找到资源
- 405 Method Not Allowed:服务器不支持该方法
- 500 Internal Server Error:与 400 类型,是个笼统通用的错误码,服务器器发生了什么错误,我们并不不知道。
具体含义 | 常见的状态码 | |
---|---|---|
1×× | 提供信息,表示目前是协议处理的中间状态,还需要后续的操作 | 常见的状态码 |
2×× | 成功,报文已经收到并被正确处理 | 200 |
3×× | 重定向,资源位置发生变动,需要客户端重新发送请求 | 301,302 |
4×× | 客户端错误,请求报文有误,服务器无法处理 | 400,403,404 |
5×× | 服务器错误,服务器在处理请求时内部发生了错误 | 500 |
HTTP常见的字段有哪些?
Host 字段:客户端发送请求时,用来指定服务器器的域名。
Content-Length 字段:服务器器在返回数据时,会有 Content-Length 字段,表明本次回应的数据字节长度。
Connection 字段:最常用于客户端要求服务器器使用 TCP 持久连接,以便其他请求复用。
Content-Type 字段:用于服务器器回应时,告诉客户端,本次数据是什什么格式。
HTTP请求协议是一个文本。
-
首行:HTTP方法 请求的URL HTTP版本号
-
首部(请求头)header
header就是一堆键值对,键值对和键值对之间,使用换行来分割,键和值之间,使用冒号+空格来分割。
header中具体有多少行是不固定的,具体是使用一个空行来作为结束标记 -
空行
通过这个空行来表示header部分结束了。
-
正文body
有的请求有正文,有的请求没有正文。 -
HTTP响应的格式
-
首行
HTTP协议版本号 状态码 状态码描述 -
协议头(header)
-
空行
-
正文
HTTP在传输层依赖TCP协议,TCP是面向字节流的,如果没有这个空行,就会出现“粘包问题”
对URL的详细分析
-
地址,域名:例如www.baidu.com
本质上是一个IP地址,写成域名是为了方便记忆。地址后面还可以带一个冒号,冒号后面可以写一个端口号,表示要访问服务器的端口,不写就代表使用默认的端口号,对于HTTP协议来说,默认的端口号是80,对于HTTPS来说,默认的端口号是443. -
URL中的路径
同一个网址中的路径不同,代表要访问服务器上不同的资源。 -
URL中的参数
键值对之间通过&来分割,键和值之间使用=来分割。使用?来作为起始标志。 -
URL中的片段标识符 #
使用较少,通常用于定位一个HTML页面的具体位置。
URL的目的就是来区分一个网络上唯一资源
- 先通过服务器地址,定位到一个具体的服务器
- 再通过端口号定位到一个具体的应用程序
- 在通过路径定位到这个应用程序管理的一个具体资源
- 在通过查询字符串对这个具体资源的要求作出进一步的解释
- 最后通过片段标识来确定定位到这个资源的哪个部分
URL encode与decode
为了解决在query string中如果包含了 “: / ? = &”等特殊符号,导致浏览器/服务器解析URL时出错的问题。引入了URL encode与decode
URL encode:把特殊字符,转成转义字符
URL decode:把转义字符,还原成原来的字符
转义就是把特殊字符里面的值,按照十六进制来表示,每个字节在前面放一个%
虽然浏览器会自动对特殊符号进行encode,但是有时候自己手动构造的URL,不一定能自动encode。稳妥起见,如果需要自己构造URL时,带有特殊符号的时候,要手动encode,否则可能导致请求失败。
请求中的方法
HTTP协议中GET和POST两个方法有什么区别?
两者没有本质区别,但在细节上还是有区别。
- 数据位置:GET把自定义数据放到query string,POST把自定义数据放到body
- 语义区别:GET一般用于“获取数据”,POST一般用于提交数据
- 幂等性:GTE请求一般会设计成“幂等”的,POST请求一般不要求设计成“幂等”【某个请求,执行一次和执行多次没有区别,如果能做到这一点,就称为“幂等”】
- 可缓存:GET请求一般会被缓存,POST请求一般不能被缓存
哪些方式会触发HTTP GET请求
- 直接在浏览器中输入URL,就会触发一个HTTP请求。
- HTML页面中的一些特殊标签,link(引入CSS),img(图片),scrip(引入JS)【加载触发】,a(超链接)【点击触发】也会触发HTTP的GET请求。
- form表单
- ajax
- 使用java代码/其他的库
- 通过Linux下的wget/curl
- 通过第三方工具,postman这类工具
通过情况下,GTE的body为空,但是可以自己构造一个body不为空的GET请求。
关于GET请求的URL长度的问题
GET的URL长度的上限以权威的RFC标准文档为准,在RFC标准文档中,HTTP协议,RFC2616标准,对于URL的长度,是没有做出限制的。
标准只是一份文件,实际开发的时候要遵守标准,但是同时也要看别人是不是严格遵守了标准。现在使用的chrome浏览器,对于URL的长度是能够支持的非常长的,一般来说不用担心长度问题。
构造POST请求的方式
- form表单
- ajax
- 第三方工具
POST请求的特点
- 首行第一部分为POST
- URL的query string一般为空,但是,也可以加上query string
- header部分有若干个键值对
- body部分一般不为空,但是,如果body为空,也是完全可行的
——————————————————————————————————————————
关于GET和POST传输的数据量
有的资料上说“GET传输的数据量小,POST传输数据量大”(不科学)。标准没有规定GET的URL的长度,也没有规定POST的body的长度,传输数据量多少,完全取决于不同浏览器和不同服务器之间的实现区别。
关于GET和POST传输数据类型
有的资料说“GET只能传输文本数据,POST可以传输二进制”(不科学),GET的query string虽然无法直接传输二进制数据,但是可以针对二进制数据进行url encode
Host键值对
一般来说是Host中的内容和URL中的地址是一致的,但是也不绝对
Content-Length
表示body的长度,单位是字节,如果没有body(GET),此时就可以没有Content-Length
Content-Type
表示body中的数据格式的类型。
- appLication/x-www-form-urlencoded:form表单提交的数据格式,此时body的格式形如
name=lisi&pass=123456
- multipart/form-data:form表单提交的数据格式(在form标签加上enctyped=“multipart/form-data”).通常用于提交图片/文件。body格式形如
Content-Type:multipart/form-data; boundary=----
WebKitFormBoundaryrGKCBY7qhFd3TrwA
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"
title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png
PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
- application/json:数据为json格式,body格式形如:
{"username":"123456789","password":"xxxx","code":"jw7l","uuid":"d110a05ccde64b16
a861fa2bddfdcd15"}
User-Agent键值对
描述了浏览器和操作系统的版本信息,形如:
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
目前的UA已经失去了最初用于区分操作系统和浏览器版本的不同,以达到有选择性的显示图片,视频的显示问题,现在更多的用于区分PC端和移动端。
Referer键值对
表示当前页面是从哪来的,直接在浏览器中输入URL/点击收藏夹打开的页面是没有Referer。
Cookie
-
Cookie是浏览器访问服务器后,服务器传给浏览器的一段数据;浏览器需要保存这段数据,不得轻易删除;此后每次浏览器访问服务器,都必须带上这段数据。
-
Cookie的两个作用:第一个作用是识别用户身份,第二个作用是记录历史。
如何使用代码来构造HTTP请求
- 直接在浏览器中输入URL
- 使用form表单(可以构造GET和POST)
- 使用ajax(可以构造各种请求)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>使用ajax构造http请求</title>
<!--引入第三方库jquery-->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<script>
// 基于 jQuery 里面的 ajax 来进行使用
// $ 就是jquery中已经定义好的一个对象
// jquery中的所有api其实都是$对象的方法
$.ajax({
type: 'GET',
url: ' http://www.baidu.com/index.html',
success:function (data,status) {
// data就是响应的body,status就是响应的状态码
console.log(status);
console.log(data);
}
});
</script>
</body>
</html>
ajax为了保证安全性,要求发起ajax请求的页面,和接收ajax请求的服务器,应该在同一个域名下。
如果发起请求的页面对应的域名和接收ajax请求的服务器的域名,如果两个域名不相同,就认为是一次跨域请求。
HTTP(1.1)的优点有哪些
- 简单
HTTP 基本的报文格式就是 header + body ,头部信息也是 key-value 简单文本的形式,易于理解,降低了了学习和使用的门槛。 - 灵活和易于扩展
HTTP协议里的各类请求方法、URI/URL、状态码、头字段等每个组成要求都没有被固定死,都允许开发人员自定义和扩充。
同时 HTTP 由于是工作在应用层,则它下层可以随意变化。HTTPS 也就是在 HTTP 与 TCP 层之间增加了了 SSL/TLS 安全传输层。 - 应用广泛和跨平台
HTTP协议的缺点
- 无状态双刃剑
无状态的好处,因为服务器器不不会去记忆 HTTP 的状态,所以不不需要额外的资源来记录状态信息,这能减轻服务器器的负担,能够把更更多的 CPU 和内存用来对外提供服务。
无状态的坏处,既然服务器器没有记忆能⼒力力,它在完成有关联性的操作时会非常麻烦。 - 明文传输双刃剑
- 不安全的缺点
Session和Cokkie
因为HTTP协议是一个无状态协议,即Web应用程序无法区分收到的两个HTTP请求是同一个浏览器发出的。
Cookie是HTTP协议中的一个字段。
Cookie怎么产生:是由服务器产生的,通过HTTP响应的Set-Cookie字段来进行设置
Cookie存在哪里:Cookie在浏览器(客户端)存储
Cookie怎么用:会在下次请求中自动被添加到请求中,发给服务器
Cookie存的是什么:Cookie就是一串字符串,键值对结构的字符串。
如果说Cookie是客户端的机制,那么Session就是服务器端的机制。
可以把Session简单理解为一个hash表,key就是sessionId,value就是程序员自定义的数据(里面可以存储用户的身份信息)
HTTP 与 HTTPS 有哪些区别?
- HTTP 是超文本传输协议,信息是明文传输,存在安全风险的问题。HTTPS 则解决 HTTP 不安全的缺陷,在 TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议,使得报文能够加密传输。
- HTTP 连接建立相对简单, TCP 三次握手之后便可进行 HTTP 的报文传输。而 HTTPS 在 TCP 三
次握手之后,还需进行 SSL/TLS 的握手过程,才可进入加密报文传输。 - HTTP 的端口号是 80,HTTPS 的端口号是 443。
- HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。
HTTPS传输过程
1.客户端先从服务器获取到证书。证书中包含了公钥。
2.客户端对证书进行校验
3.客户端生成一个对称密钥,使用公钥对对称密钥进行加密,发送给服务器。
4.服务器得到这个请求之后,使用私钥解密,得到对称密钥。
5.客户端发出后续的请求,后续的请求都是使用这个对称密钥加密的。
6.收到的数据也都是使用这个对称密钥解密的。
以上传输的过程就是怎么安全的把(对称密钥)安全的传递过去,使用非对称加密中的(公钥和私钥)。
本质就是利用 非对称加密 对 对称加密的 密钥 进行加密和解密,同时引入了证书携带公钥保证了安全性。
传输层协议UDP和TCP
负责端对端的数据传输,只考虑起点和终点,不考虑中间过程。
传输层是操作系统内核实现的,因此谈到的传输层协议,一般都是指线程的一些协议,很少会涉及“自定制”。
TCP协议的报文格式
序列号:在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。
确认应答号:指下一次「期望」收到的数据的序列号,发送端收到这个确认应答以后可以认为在这个序号以前的数据都已经被正常接收。用来解决不丢包的问题。
控制位:
- ACK:该位为 1 时,「确认应答」的字段变为有效,TCP 规定除了最初建立连接时的 SYN
包之外该位必须设置为 1 。 - RST:该位为 1 时,表示 TCP 连接中出现异常必须强制断开连接。
- SYN:该位为 1 时,表示希望建立连接,并在其「序列号」的字段进行序列号初始值的设定。
- FIN:该位为 1 时,表示今后不会再有数据发送,希望断开连接。当通信结束希望断开连接时,
通信双方的主机之间就可以相互交换 FIN 位为 1 的 TCP 段。
【TCP报头/首部(header) | TCP数据/载荷(payload)】
首部前面一共是20个字节,options部分,范围就是0-40个字节,所以首部最长是60个字节。
这六个比特位,标识了这个TCP数据报是一个什么类型的数据报。
为什么需要 TCP 协议? TCP 工作在哪一层?
IP 层是「不可靠」的,它不保证网络包的交付、不保证网络包的按序交付、也不保证网络包中的数据
的完整性。
因为 TCP 是一个工作在传输层的可靠数据传输的服务,它能确保接收端接收的网络包是无损坏、无间
隔、非冗余和按序的。
什么是TCP?
TCP 是面向连接的、可靠的、基于字节流的传输层通信协议。
- 面向连接:一定是「一对一」才能连接,不能像 UDP 协议可以一个主机同时向多个主机发送消
息,也就是一对多是无法做到的; - 可靠的:无论的网络链路中出现了怎样的链路变化,TCP 都可以保证一个报文一定能够到达接收
端; - 字节流:消息是「没有边界」的,所以无论我们消息有多大都可以进行传输。并且消息是「有序
的」,当「前一个」消息没有收到的时候,即使它先收到了后面的字节,那么也不能扔给应用层
去处理,同时对「重复」的报文会自动丢弃。 - 全双工:一个socket,既能读,也能写
什么是TCP连接?
简单来说就是,用于保证 可靠性 和 流量控制维护 的某些状态 信息,这些信息的组合,包括Socket、序列号和窗口大小称为连接。
- Socket:由 IP 地址和端口号组成
- 序列号:用来解决乱序问题等
- 窗口大小:用来做流量控制
建立一个 TCP 连接是需要客户端与服务器端达成上述三个信息的共识。
如何唯一确定一个TCP连接?
TCP四元组可以唯一确定一个连接,四元组包括如下。
- 源地址
- 源端口
- 目的地址
- 目的端口
源地址和目的地址的字段(32位)是在 IP 头部中,作用是通过 IP 协议发送报文给对方主机。
源端口和目的端口的字段(16位)是在 TCP 头部中,作用是告诉 TCP 协议应该把报文发给哪个进程。
如何在Linux系统中查看TCP状态?
TCP 的连接状态查看,在 Linux 可以通过 netstat -napt 命令查看。
保证可靠性的核心是确认应答【可靠性】
发送方法数据给接收方,接收方就回应一个应答报文。如果发送方收到了这个应答报文,那么认为是对方已经收到了。如果发送方发送了多条数据,接受方也回复了多条数据,但是网络上存在一种常见的情况:后发先至。因此不能就单纯的通过收到数据的顺序来确定逻辑,就需要对应答进行编号(报文中的序号与确认序号)。
TCP传输数据是按照字节来算的(面向字节流),TCP的序号和确认序号,是以字节为单位进行编号的。
超时重传【可靠性】
数据在传输的过程中如果发生丢包,就要进入超时重传的机制中,每次重传的等待时间会逐渐增加。
如果网络大体是正常的,那么出现连续两次甚至连续三次都丢包的概率,是非常低的。
如果重传导致数据重复了怎么办?
接收方收到的数据会先放在内核的“接受缓冲区中”(一段内存,每个socket都有),按照序号来进行去重,此时在应用程序中读取数据,读到的结果就是不带重复的。
连接管理【可靠性】
TCP是有连接的,连接管理就是如何建立连接(三次握手),如何断开连接(四次挥手)
本质上,就是A向B请求连接,B给予回应,B也向A请求连接,A给予回应。
本来应该是“四次握手”,但是中间两次操作,是可以合在一起的。这两个操作在时间上是同时发生的。
正常情况下,SYN这一位是0,在尝试请求连接的请求中,这一位是1。
正常情况下,ACK这一位是0,在进行确认应答的时候,这一位是1。
为什么要三次握手,为什么要建立连接?
- 通过三次握手的过程,来确认A和B之间的传输是通畅的,尤其是要确认,A和B各自的发送能力和接收能力是否正常。
- 协商参数,通过三次握手,让A和B之间通通气,选择一些传输中合适的参数,例如,TCP的序号从几开始。
四次握手也可以,但没有必要。两次握手不行。
三次握手过程中涉及到的一些状态转换
- LISTEN:手机开机,信号良好,随时可以打入电话
当我们创建好ServerSocket实例的时候,就进入了LISTEN状态
2.ESTABLISHED:接通了电话,双方可以说话了
代码中accept返回了,得到了一个clientSocket
tcp 为什么要三次握手,两次不行吗?为什么?
因为客户端和服务端都要确认连接,①客户端请求连接服务端;②针对客户端的请求确认应答,并请求建立连接;③针对服务端的请求确认应答,建立连接;
两次无法确保A能收到B的数据;
四次挥手
为什么挥手需要四次?
- 关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数
据。 - 服务器收到客户端的 FIN 报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理
和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端来表示同意现在关闭连接。
从上面过程可知,服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK 和 FIN 一般都
会分开发送,从而比三次握手导致多了一次。
结束报文段:FIN
ACK和FIN为什么不合并?
对于B来说,ACK和FIN的触发实际是不一样的
B只要收到FIN就会立即触发ACK,这个事是内核完成的
B发送FIN的实际是用户代码控制的(代码中出现了socket.close()这样的操作的时候,才会触发FIN)
四次挥手中的状态变化
CLOSE_WAIT:服务器收到FIN之后进入的状态,等待用户代码调用close,来发送FIN~
TIME_WAIT:表示的客户端收到了FIN之后进入了TIME_WAIT
这个状态存在的意义主要就是处理最后一个ACK丢包
出现丢包的话,客户端就会重传FIN
如果服务器上出现大量的CLOSE_WAIT,是代码出现bug,close没有及时被调用到。
四次挥手是否可能变成三次挥手?
有可能,虽然ACK和FIN不是同时的,但是在延时应答和捎带应答的情况下使有可能合并在一起的。
滑动窗口【效率】
在这个过程中,发送方要花很多时间来等,这个等待其实就浪费了大量的时间。
窗口大小就是指无需等待确认应答,而可以继续发送数据的最大值。如果窗口越大,整体的效率就越高。但是也不能无限大,完全不等ACK。
针对多个ACK在网络上传输的情况,如果后面的ACK先到,表示之前的数据也被对方收到了,那么之前的ACK收到或没有收到已经不重要了。
如果在滑动窗口的场景中出现丢包了,怎么办?
没有关系,只要不是全丢就好了,因为有快速重传机制,如果发生丢包,接受方就会多次索要丢失的数据,收到三个同样的确认应答是则进行重发,后续已达到的数据保存在缓冲区中。当丢失的数据重传之后,后续的数据
流量控制【可靠性】
对滑动窗口的进一步补充,窗口太大太小都不合适,此处流量控制室基于接收方的处理能力来限制窗口大小(接收缓冲区的剩余空间)的。
返回的ACK会把缓冲区的剩余空间发送给对方。
如果窗口为0,发送方不再发送数据,但是为了能够查询当前接收方的窗口大小,每隔一段时间,还会再来触发一个窗口探测包,通过这个包(不传输具体的业务数据)触发ACK,在这个ACK中就能够知道当前窗口的大小了。
拥塞控制【效率】
站在另外一个角度来限制发送方的窗口大小。
站在一个宏观的角度来看待这个问题,把整个中间的链路都看成了一个整体,只看结果。
先使用一个较小的窗口来传输数据,看看是否丢包,如果不丢包,说明网络比较通畅,如果丢包,说明网络发生拥堵。
当网络通畅的时候,就逐渐加大发送速率,当网络出现丢包的问题,就立即降低发送速率。如果达到阈值,就从指数增长变成线性增长。
通过这样的方式,就可以逐渐实验出一个比较合适的窗口大小。
真实的发送窗口的大小=min(流量控制的窗口,拥塞控制的窗口)
延时应答【效率】
在延时应答的这段时间,应用程序就会消费一部分数据,此时缓冲区的剩余空间就更大了。
捎带应答
正常情况下,服务器内核收到数据,就会立即返回ack,但是由于有了延时应答,返回的ACK不是立即返回,而是等一会,正好在这段时间,服务器要返回业务上的response了,此时就可以把这个ACK和response合二为一,把两个包变成一个包。
面向字节流【其他】
在这种面向字节流的情况下,需要注意一个重要的问题:粘包问题
应用程序从接收缓冲区读数据的时候,不知道从哪到哪是一个完整的应用层数据报。
解决办法(核心就是明确应用层数据中,包和包之间的边界)
- 给应用层数据设定“结束符”/“分隔符”
约定,每个应用层数据报一定以;结尾 - 给应用层数据设定“长度”
设定包的长度,约定每个应用层数据报的前4个字节,存储数据报的长度
异常情况【其他】
常见的异常情况:
1.进程终止
不管进程是怎么终止的,本质上都会释放对应的PCB,也会释放对应的文件描述符,一样会触发四次挥手。
“进程终止”不代表连接就终止,进程终止其实就相当于调用了socket.close()而已
2.机器重启
机器重启的时候,其实也是先杀进程,仍然是进行四次挥手
3.机器掉电/网线断开
①掉电的是接收方
此时另外一边还在发送数据,此时显然发送发不会再有ACK
于是就会超时重传,重传几次之后,就会尝试重置连接,用到复位报文段(RST),再然后发送方就会放弃这个连接,把连接对应的资源就回收了。
②掉电的是发送方
此时另外一方在尝试接受数据,此时接受不到任何数据
接受方如何知道,发送方式挂了,还是说发送方暂时还没发呢?
此时接收方采取的策略,就是“心跳包”机制(也叫做“保活”)
每隔一段时间,向对方发送一个PING包,期待对方返回一个PONG包
如果PING包发过去,过了很久还没有PONG,并且重试几次也不行,此时就认为对方已经挂了。
如何基于UDP协议实现可靠传输?
看似在问UDP,其实在问TCP
1.实现确认应答机制,把每个数据接受到之后,都要反馈一个ACK(不是内核返回,而是应用程序自己定义一个ack包,发送回去)
2.实现序号/确认序号,以及实现去重
3.实现超时重传
4.实现连接管理
5.要想提高效率,实现滑动窗口
6.为了限制滑动窗口,实现流量控制/拥塞控制
7.实现延时应答,捎带应答,心跳机制
UDP的特性
1.无连接
2.不可靠
3.面向数据报
4.全双工
无连接:socket创建好之后,就可以立即尝试读写数据了
有连接:socket创建好了之后,还需要建立连接,连接建立完了,再通过accept获取到连接,才能进行读写数据。
可靠/不可靠:
面向数据报:读写数据都是以DatagramPacket为单位进行的
面向字节流:读写数据直接以byte[]为单位
全双工:一个socket,既能读(socket.receive),也能写(socket.send)
几个概念:
1.端口号
端口号的用途:标识一个进程,就可以区分出当前收到的数据要交给哪个进程来处理。
端口号是一个整数,是一个两个字节的整数,0-65535(没有负数)
0-1023 这些端口,称为“知名端口号”。
通常情况下,两个进程无法绑定到同一个端口号。
一个进程可以绑定多个端口,绑定,不是把进程和端口绑定,而是把socket(socket就是文件,一个进程里可以有很多文件,也就可以有很多socket,每个socket都可以绑定到不同的端口)和端口绑定。
进程是通过同一个网卡来传输数据的,让每个进程分别绑定不同的端口号,数据包中有一个“目的端口”字段,会根据目的端口找到对应的端口号的进程,然后把数据交给对应的进程。
PID:每次进程启动之后,都在发生改变(系统自动分配)
UDP协议报文格式:
关于UDP长度:
整个UDP数据报的长度,使用2个字节的数据来表示,2个字节能表示的数据范围是0-65535byte,也就是一个UDP数据报,最大就是64KB。如果报文长度超过64KB,此时就可能丢失一部门数据,解决办法是改用TCP,TCP对于数据的长度没有限制。
实际使用的校验的算法有很多,其中比较常见的有crc(循环冗余校验)和md5校验。
crc(循环冗余校验)
假设有一串数据,把它当成二进制的数据,依次按照字节为单位,取出数据,然后把这些数据进行累加。发送以前算一遍crc,接收到之后也算一遍crc,如果这个数据发送前和发送后,数据内容不变,得到的crc也是一致的。
如果传输过程中出现了比翻转,接受到的内容和发送的内容就不一样了,此时算出来的两份crc也就是大概率不相同的。
TCP 和 UDP 区别
- 连接
TCP 是面向连接的传输层协议,传输数据前先要建立连接。
UDP 是不需要连接,即刻传输数据。 - 服务对象
TCP 是一对一的两点服务,即一条连接只有两个端点。
UDP 支持一对一、一对多、多对多的交互通信 - 可靠性
TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按需到达。
UDP 是尽最大努力交付,不保证可靠交付数据。 - 拥塞控制、流量控制
TCP 有拥塞控制和流量控制机制,保证数据传输的安全性。
UDP 则没有,即使网络非常拥堵了,也不会影响 UDP 的发送速率。 - 首部开销
TCP 首部长度较长,会有一定的开销,首部在没有使用「选项」字段时是 20 个字节,如果使
用了「选项」字段则会变长的。
UDP 首部只有 8 个字节,并且是固定不变的,开销较小。 - 传输方式
TCP 是面向字节流,流式传输,没有边界,但保证顺序和可靠。
UDP 是一个包一个包的发送,是有边界的,但可能会丢包和乱序。 - 分片不同
TCP 的数据大小如果大于 MSS 大小,则会在传输层进行分片,目标主机收到后,也同样在传输
层组装 TCP 数据包,如果中途丢失了一个分片,只需要传输丢失的这个分片。
UDP 的数据大小如果大于 MTU 大小,则会在 IP 层进行分片,目标主机收到后,在 IP 层组装完
数据,接着再传给传输层,但是如果中途丢了一个分片,则就需要重传所有的数据包,这样传输
效率非常差,所以通常 UDP 的报文应该小于 MTU。
TCP和UDP应用场景
1.如果需要可靠性,选TCP
2.如果传输的单个数据报比较长(超过64K),使用TCP
3.如果特别注重效率,优先考虑UDP
4.如果需要广播,优先考虑UDP
一份数据同时发给多个主机,UDP自身就支持广播,但是TCP自身是不支持的,就只能在应用层中通过多个连接,轮询的方式给每个主机发送数据(伪广播)
为什么 UDP 头部没有「首部长度」字段,而 TCP 头部有「首部长度」字段呢?
原因是 TCP 有可变长的「选项」字段,而 UDP 头部长度则是不会变化的,无需多一个字段去记录
UDP 的首部长度。
网络层协议之IPV4
IPv4协议:Internet网络层最核心的协议。定义了如何封装上层协议( 如UDP、 TCP) 的报文段;定义了Internet网络层寻址( IP地址) 以及如何转发IP数据报等内容。
协议头格式简单介绍
版本(4位):4位能表示 0到15
4位首部长度:0-15 单位是4个字节
IP数据报的首部长度和数据长度都是可变长的,但总是4字节的整数倍。对于IPv4,4位版本字段是4。4位首部长度的数值是以4字节为单位的,最小值为5,也就是说首部长度最小是4x5=20字节,也就是不带任何选项的IP首部,4位能表示的最大值是15,也就是说首部长度最大是60字节。
区分服务(8位):
8位TOS字段有3个位用来指定IP数据报的优先级(目前已经废弃不用),还有4个位表示可选的服务类型(最小延迟、最大呑吐量、最大可靠性、最小成本),还有一个位总是0。
16位总长度(字节数):
总长度是整个数据报(包括IP首部和IP层payload)的字节数。每传一个IP数据报,16位的标识加1,可用于分片和重新组装数据报。
16位标识,3位标志,13位片偏移:这三个字段辅助进行实现 拆包组包
16位标识,相当于IP数据报的身份标识
把一个数据拆成多个IP数据报的时候,这三个IP数据报的标识是相同的。
3位标志和13位片偏移用于分片。
13位片偏移,描述了当前这个包的顺序。
3位标志,第二位表示“禁止分片”,第三位表示“更多分片”,如果这一位为1表示当前这个分片就是最后一个分片,如果这一位为0表示当前这个分片不是最后一个分片。
8位生存时间(TTL):
这个字段表示一个IP数据报最多在网络上存活多久,这个TTL不是一个“时间”概念,而是一个“次数”
源主机为数据包设定一个生存时间,比如64,每过一个路由器就把该值减1,如果减到0就表示路由已经太长了仍然找不到目的主机的网络,就丢弃该包,因此这个生存时间的单位不是秒,而是跳(hop)。协议字段指示上层协议是TCP、UDP、ICMP还是IGMP。然后是校验和,只校验IP首部,数据的校验由更高层协议负责。IPv4的IP地址长度为32位。
TTL的目的是为了防止这个IP数据报出现环路转发的情况
8位协议:
通过8位协议来指定传输层使用哪个协议来解析数据。
类似,传输层(例如TCP,UDP)的报头中的 目的端口就是在指定应用层使用哪个协议。
16位首部校验和:
类似于crc循环检验,只需要校验首部即可,载荷部分(就是一个完整的TCP/UDP数据报)其实已经由TCP或者UDP进行校验了。
32位源IP地址:发送人地址
32位目的IP地址:接收人地址
IP协议核心功能
1.地址管理:能够通过一系列的规则,把网络上的设备的地址给描述出来。
2.路由选择:根据当下的源地址和目的地址,规划处一条合适的路径。
在IPV4协议,ip地址是通过32位的整数表示,通过“点分十进制”,把一个32位的数字分成4份,每一份就是8bit(一个字节),八个比特位能表示的范围是【0,255】
如何解决IP地址不能分配的问题?
1.动态分配IP
接入网络的设备分配IP地址,没接入网络的设备就不分配,但是这种方法并不能从根本上解决问题。
2.NAT机制,网络地址替换
不同局域网中的ip地址可以重复,但是经过路由器到达公网的ip地址不能重复。(如图所示)
同一个局域网里的足迹,网络号要相同,主机号不能相同。
IP地址子网掩码都是32位的2进制,为了方便记忆转成10进制,通过子网掩码来区分网络位和主机位,子网掩码跟IP地址一一对应,子网掩码为1的是网络位,为0的是主机位。
如:192.168.1.2 掩码255.255.255.0 。网络位192.168.1 主机位是2
路由选择
这里的路由指的是IP协议中的“路径规划功能”
IP协议中,数据到达某个路由器之后,当前路由器并不知道网络整体的环境,当前路由器只是知道它附近的情况,IP协议寻路的过程,是一个“探索式”的过程。
数据链路层协议之以太网
数据链路层的作用
负责两个相邻节点之间数据的传输
核心协议
以太网(涉及到数据链路层+物理层),是一种技术标准。规定了网络拓扑结构,访问控制方式,传世速率等。
在不同网络层次上,描述一个数据,使用的术语是不同的:
传输层:一个数据段(segement),同步报文段(syn),确认报文段(ack),结束报文段(fin),复位报文段(rst)
网络层:一个数据报(packet)
数据链路层:一个数据帧(frame)
以太网的帧格式
源地址和目的地址是指网卡的硬件地址(也叫MAC地址),长度6个字节,48位,MAC地址是在出厂时固化的。
帧协议类型字段有三种值,分别对应IP,ARP,RARP
帧末尾是CRC校验码
MAC地址
通过ipconfig/all 命令查看MAC地址。
MTU
物理层存在这样的硬性限制,对应的数据链路层的数据帧,是有一定的大小范围。这个范围指标就称为MTU。
IP数据报分包,往往不是因为达到了IP的上限才分的包,而是因为达到了MTU的上限才分的包。
ARP协议
这个协议是一个“辅助性”的协议,这个协议横跨数据链路层和网络层。
作用就是根据IP查询对应的MAC地址。
工作的过程是在设备接入网络的时候,先广播一个ARP请求(当前局域网中广播),收到这个请求的设备返回ARP响应(包含了每个设备的IP和MAC)。