OSI五层模型
前言
计算机网络概念: 计算机网络是利用通信线路和通信设备,将地理位置不同的、功能独立的多台计算机互连起来,以功能完善的网络软件来实现资源共享和信息传递,就构成了计算机网络系统。
一、应用层
DNS协议
HTTP协议
HTTP是超文本传输协议。它是基于TCP协议的应用层传输协议,即是客户端和服务端的数据传输一种规则。HTTP协议本身是一种无状态的协议(无状态:是指每一个HTTP请求的发送、传输、接收均相互独立的,它们之间没有任何的上下文关系)。 HTTP有两种连接方式。 1、短连接(非持续连接):指服务端对于来自客户端的每一个请求均建立一个连接,当服务端响应请求后就关闭连接,不为其他的请求而持续连接。 2、长连接(持续连接):指服务端响应请求后,不关闭连接,为之后的其他请求保持连接状态。 两种方式的比较: 由于HTTP协议是基于TCP协议的应用层传输协议,故每一次的创建连接,都需要额外的性能开销,长连接避免了短连接的为每次请求而创建连接的性能开销。 工作过程: 1、地址解析
假如客户端浏览器请求(url)这个界面,http://localhost.com:8080/index.html
从这个url可以解析出传输协议、主机号、端口号、资源路径
在这个例子的url可以得到
协议:http
主机号:localhost.com(这个主机号会通过DNS域名解析得到ip地址)
端口号:8080
资源路径:/index.html
2、HTTP请求数据包
GET http:
User-Agent : wget/1.12 ( linux-gnu)
Host: www . baidu . com
Connection : close
第一行是请求行,其中的“GET”是请求方法,表示客户端以只读的方式向服务器获取资源,不对服务器产生其他的影响。 HTTP有9种请求方法:
请求方法 | 含义 |
---|
GET | 申请获取资源,不会对服务器产生其他的影响,服务器会返回所获取的资源数据 | HEAD | 该方式与GET类似,但只要求服务器返回头部信息,不需要传输任何实际内容数据 | POST | 向服务器提交数据的方法,会对服务器产生影响,提交的数据可能需要服务器动态创建新的资源,也可能对旧的资源进行修改 | PUT | 上传某个资源 | DELETE | 删除某个资源 | TRACE | 要求目标服务器返回HTTP请求的原始内容,可用来查看中间服务器对HTTP请求的影响 | OPTIONS | 查看服务器对特定的URL支持哪些请求方法。也可以设置URL为*,则可以获得服务器支持的所有请求方法。 | CONNECT | 用于某些的代理服务器,可以将HTTP请求的连接转为一个安全隧道 | PATCH | 对某个资源做部分修改 |
其中的GET、HEAD、TRACE、OPTIONS视为安全方法,因为它们只从服务器获取资源,不会产生其他的影响,而POST、PUT、DELETE、PATCH则会影响服务器的资源。 另一方面,GET、HEAD、PUT、DELETE、TRACE、OPTIONS等请求方法被视为等幂的,即为多次连续的、重复的请求和只和一次的请求效果是一样的。而POST、PATCH等是连续发送或重复发送都可能会影响服务器。 HTTP请求的内容中第2~4行都是HTTP请求的头部字段,一个请求可以含有多个字段,每一个字段占用一行,字段包括字段名、冒号、空格、字段值,请求中字段顺序可任意的。 Host字段(目标主机号):HTTP请求中必须包含的头部字段。 Connection字段 (连接状态):该字段表示通知对方在响应请求后如何处理连接;字段值一般为close和keep-alive。close表示服务器响应请求后,要求服务器关闭TCP连接;而keep-alive表示要求服务器在响应请求后继续保持连接,让该连接为其他请求服务。 注意:在所有的头部字段之后,请求中必须包含一个空行,用来标识头部字段的结束,该空行不能包括任意字符(空格也不行),在空行之后的下一行才是所需要传输的数据内容的开始(消息体),如果请求中包含消息体,则在头部字段中必须设置“Content-Length”,表示消息体的长度。 请求的格式如下: 请求行 (多个)头部字段,每一个字段一行 空行(不能含有其他字符) 传输的数据内容(可选,包含则需要在头部字段添加“Content-Length”字段 3、HTTP响应 HTTP响应部分内容如下: 第一行是状态行,服务端和客户端使用的HTTP协议的版本号必须相同(这里是HTTP/1.0),后面“200 OK”是状态码和状态信息。常见的状态码和状态信息如下: 第2~7行是HTTP应答的头部字段。其表示方法和HTTP请求的头部字段一样。 需要注意的“Set-Cookie”头部字段,我们先了解一下Cookie。 前面讲到了HTTP协议是无状态的,每一个HTTP请求都相互独立,但在交互式的Web程序中,这种的无状态HTTP就显得力不从心了,比如服务器要处理后续的请求是客户端之前已请求过的HTTP请求,则客户端需要重新重传这些信息。常见的解决方法就是Cookie,是一种服务器发送给客户端的特殊信息,它能让HTTP请求承上启下,服务器将在HTTP应答的头部字段中加入“Set-Cookie”字段,发送给客户端,客户端会将Cookie数据缓存到本地,而客户端每次发送HTTP请求时需要添加“Cookie”字段,服务器解析该HTTP请求的字段时,可以区分不同的客户。Cookie常见的应用有浏览器的自动登录、浏览记录、保存密码等。Cookie还会在下面的章节会详细介绍。
Cookie详解
Cookie的定义:Cookie其实就是一些数据信息,类型为“小型文本文件”,存储于电脑上的文本文件中。 Cookie的应用场景: 浏览器的浏览记录、自动登录、保存密码、身份认证等。 其实就是游览器保存了我们的cookie,里面记录了一些信息,当然,这些cookie是服务器创建后返回给游览器的。游览器只进行了保存。 Cookie的表示: 一般情况下,cookie是以键值对进行表示的(key-value),例如name=jack,这个就表示cookie的名字是name,cookie携带的值是jack。 Cookie的常用属性 Name:这个是cookie的名字 Value:这个是cookie的值 Path:这个定义了Web站点上可以访问该Cookie的目录 Expires:这个值表示cookie的过期时间,也就是有效值,cookie在这个值之前都有效。 Size:这个表示cookie的大小 Cookie的传输:
1、HTTP的请求中的Cookie: 我们在发送HTTP请求时,发现游览器将我们的cookie都进行了携带(注意:游览器只会携带在当前请求的url中包含了该cookie中path值的cookie),并且是以key:value的形式进行表示的。多个cookie用;进行隔开。 以头部字段Cookie : name=jack;password=123456 2、HTTP的应答中的Cookie: 我们发现在HTTP响应中, cookie的表示形式是,Set-Cookie:cookie的名字,cookie的值。如果有多个cookie,那么在HTTP响应中就使用多个Set-Cookie进行表示。 Cookie的生命周期: cookie有两种存储方式,一是会话性、二是持久性 1、会话性:如果cookie为会话性,那么cookie仅会保存在客户端的内存中,当我们关闭客服端时cookie也就失效了 2、持久性:如果cookie为持久性,那么cookie会保存在用户的硬盘中,直至生存期结束或者用户主动将其销毁。 cookie我们是可以进行设置的,我们可以人为设置cookie的有效时间,什么时候创建,什么时候销毁。
4、HTTP的版本(HTTP 1.0/1.1/2.0) HTTP1.0 规定了请求头和请求尾,响应头和响应尾(get post) 每一个请求都是一个单独的连接,做不到连接的复用(短连接) 每一次的请求都会创建一个新的TCP连接,服务器响应请求之后会关闭连接,无法为之后的其他连接保持连接,使得网络的性能很低效。 HTTP1.1 HTTP1.1默认开启长连接,在一个TCP连接上可以传送多个HTTP请求和响应。使用 TCP 长连接的方式改善了 HTTP/1.0 短连接造成的性能开销。 支持管道(pipeline)网络传输,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。 HTTP2.0 提出多路复用。多路复用前,文件时串行传输的,请求a文件,b文件只能等待,并且连接数过多。引入多路复用,a文件b文件可以同时传输。 引入了二进制数据帧。其中帧对数据进行顺序标识,有了序列id,服务器就可以进行并行传输数据。 5、GET和POST的区别
| GET | POST |
---|
定义 | 用于向服务端获取资源,不会产生对服务端的其他影响 | 向服务端提交数据,可能会使服务端申请创建新的资源,或修改原有的旧资源的内容,对服务器产生影响 | 后退按钮/刷新 | 无害 | 数据会被重新提交(浏览器应该告知用户数据会被重新提交) | 书签 | 可收藏为书签 | 不可收藏为书签 | 缓存 | 缓存 | 不能缓存 | 编码类型 | application/x-www-form-urlencoded | application/x-www-form-urlencoded 或 multipart/form-data。为二进制数据使用多重编码。 | 历史记录 | 参数保留在浏览器历史中。 | 参数不会保存在浏览器历史中。 | 对数据长度的限制 | 是的。当发送数据时,GET 方法向 URL 添加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符) | 无限制 | 对数据类型的限制 | 只允许 ASCII 字符。 | 没有限制。也允许二进制数据。 | 安全性 | 与 POST 相比,GET 的安全性较差,因为所发送的数据是 URL 的一部分。在发送密码或其他敏感信息时绝不要使用 GET ! | POST 比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中。 | 可见性 | 数据在 URL 中对所有人都是可见的。 | 数据不会显示在 URL 中。 |
从标准上来看,GET 和 POST 的区别如下: GET 用于获取信息,是无副作用的,是幂等的,且可缓存 POST 用于修改服务器上的数据,有副作用,非幂等,不可缓存 请求过程的区别: post请求的过程: 浏览器请求tcp连接(第一次握手) 服务器答应进行tcp连接(第二次握手) 浏览器确认,并发送post请求头(第三次握手,这个报文比较小,所以http会在此时进行第一次数据发送) 服务器返回100 Continue响应 浏览器发送数据(消息体) 服务器返回200 OK响应
get请求的过程: 浏览器请求tcp连接(第一次握手) 服务器答应进行tcp连接(第二次握手) 浏览器确认,并发送get请求头和数据(第三次握手,这个报文比较小,所以http会在此时进行第一次数据发送) 服务器返回200 OK响应
报文段上的区别: GET 和 POST 只是 HTTP 协议中两种请求方式(异曲同工),而 HTTP 协议是基于 TCP/IP 的应用层协议,无论 GET 还是 POST,用的都是同一个传输层协议,所以在传输上,没有区别。 报文格式上,不带参数时,最大区别就是第一行方法名不同, 仅仅是报文的几个字符不同而已 POST 方法请求报文第一行是这样的 POST /url HTTP/1.1 GET 方法请求报文第一行是这样的 GET /url HTTP/1.1 带参数时报文的区别呢? 在约定中,GET 方法的参数应该放在 url 中,POST 方法参数应该放在 body 中 举个例子,如果参数是 name=Javanx, age=25。 GET 方法报文是这样的
GET /updateInfo?name=Javanx&age=25 HTTP/1.1
Host: localhost
POST 方法报文是这样的
POST /updateInfo HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
name=Javanx&age=25
现在我们知道了两种方法本质上是 TCP 连接,没有区别。但如果不按规范来也是可以的,可以在 URL 上写参数,然后方法使用 POST;也可以在 Body 写参数,然后方法使用 GET。当然,这需要服务端支持。 问答:
1、GET 方法参数写法是固定的吗? 在约定中,我们的参数是写在 ? 后面,用 & 分割。 我们知道,解析报文的过程是通过获取 TCP 数据,用正则等工具从数据中获取 Header 和 Body,从而提取参数。 比如header请求头中添加token,来验证用户是否登录等权限问题。 也就是说,我们可以自己约定参数的写法,只要服务端能够解释出来就行,万变不离其宗。
2、GET 方法的长度限制是怎么回事? 网络上都会提到浏览器地址栏输入的参数是有限的。 首先说明一点,HTTP 协议没有 Body 和 URL 的长度限制,对 URL 限制的大多是浏览器和服务器的原因。 浏览器原因就不说了,服务器是因为处理长 URL 要消耗比较多的资源,为了性能和安全(防止恶意构造长 URL 来攻击)考虑,会给 URL 长度加限制。
3、POST 方法比 GET 方法安全? 有人说POST 比 GET 安全,因为数据在地址栏上不可见。 然而,从传输的角度来说,他们都是不安全的,因为 HTTP 在网络上是明文传输的,只要在网络节点上捉包,就能完整地获取数据报文。 要想安全传输,就只有加密,也就是 HTTPS。
4、POST 方法会产生两个 TCP 数据包? 有些文章中提到,post 会将 header 和 body 分开发送,先发送 header,服务端返回 100 状态码再发送 body。 HTTP 协议中没有明确说明 POST 会产生两个 TCP 数据包,而且实际测试(Chrome)发现,header 和 body 不会分开发送。 所以,header 和 body 分开发送是部分浏览器或框架的请求方法,不属于 post 必然行为。 HTTP的弊端 HTTP 之所以被 HTTPS 取代,最大的原因就是不安全,至于为什么不安全,看了下面这张图就一目了然了。 由图可见,HTTP 在传输数据的过程中,所有的数据都是明文传输,自然没有安全性可言,特别是一些敏感数据,比如用户密码和信用卡信息等,一旦被第三方获取,后果不堪设想。这里可能有人会说,我在前端页面对敏感数据进行加密不就行了,比如 MD5 加盐加密。这么想就太简单了。首先 MD5 并不是加密算法,其全称是 Message Digest Algorithm MD5,意为信息摘要算法,是一种不可逆的哈希算法,也就是说经过前端 MD5 处理过的数据在服务器端是无法复原的。这里以密码举例,前端把用户密码通过 MD5 进行处理,并把得到的哈希值发送给服务器,服务器由于无法复原密码,就会直接用这个哈希值处理用户请求。所以第三方在获取这个哈希值后,可以绕过前端登录页面直接访问服务器,造成安全问题。另外,MD5 算法本身的安全性也存在缺陷,这里就不展开谈了。
总之 MD5,SHA-1 之类的哈希算法并不能让 HTTP 变得更安全。要想让 HTTP 更安全,只能使用真正的加密算法,因为加密算法可以用密钥加密或还原数据,只要确保密钥不被第三方获取,那就能确保数据传输的安全了。而这正是 HTTPS 的解决方案,那下面就来了解一下加密算法吧。
HTTPS协议
HTTPS = HTTP + SSL(安全套接层协议) / TLS(安全传输层协议) 在讲解HTTPS协议之前,需要了解HTTPS使用的加密算法。 加密算法:对称加密、非对称加密 HTTPS 解决数据传输安全问题的方案就是使用加密算法,具体来说是混合加密算法,也就是对称加密和非对称加密的混合使用,这里有必要先了解一下这两种加密算法的区别和优缺点。 1、对称加密 对称加密:顾名思义就是对数据的加密和解密都使用同一个密钥。常见的对称加密算法有 DES、3DES 和 AES 等,其优缺点如下: 一)优点: 加密速度快、算法公开、计算量小、适合加密比较大的数据。 二)缺点: 当双方使用同一个密钥传输数据时,那就避免不了密钥的传输,传输的过程有可能被第三方截获密钥,这样的对称加密也失去了意义,得不到安全的保证。 每对用户每次使用对称加密算法时,都需要使用其他人不知道的惟一密钥,这会使得发收信双方所拥有的钥匙数量急剧增长,密钥管理成为双方的负担。对称加密算法在分布式网络系统上使用较为困难,主要是因为密钥管理困难,使用成本较高。 疑惑:如果对HTTP使用对称加密算法,效果如下: 如果被第三方截获密钥,数据就会被轻松解密,那如何保证密钥传输的安全呢?可以使用非对称加密对密钥加密传输。 2、非对称加密 非对称加密:指的是服务端有一对密钥,分别为公钥和私钥。公钥加密后的密文,只能使用私钥才能解密,公钥一般对外公开,私钥只能自己含有。当客户端使用公钥对数据进行加密,然后将数据加密后的密文传输到服务端,服务端用私钥对密文进行解密。 优点: 算法公开,加密和解密使用不同的钥匙,私钥不需要通过网络进行传输,安全性很高。 缺点: 计算量比较大,加密和解密速度相比对称加密慢很多。 由于非对称加密的强安全性,可以用它完美解决对称加密的密钥泄露问题,效果图如下: 在上述过程中,客户端在拿到服务器的公钥后,会生成一个随机码 (用 KEY 表示,这个 KEY 就是后续双方用于对称加密的密钥),然后客户端使用公钥把 KEY 加密后再发送给服务器,服务器使用私钥将其解密,这样双方就有了同一个密钥 KEY,然后双方再使用 KEY 进行对称加密交互数据。在非对称加密传输 KEY 的过程中,即便第三方获取了公钥和加密后的 KEY,在没有私钥的情况下也无法破解 KEY (私钥存在服务器,泄露风险极小),也就保证了接下来对称加密的数据安全。而上面这个流程图正是 HTTPS 的雏形,HTTPS 正好综合了这两种加密算法的优点,不仅保证了通信安全,还保证了数据传输效率。 HTTPS加密过程: HTTPS数据加解密过程中数据进行对称加密,对称加密所要使用的密钥通过非对称加密传输。 HTTPS协议加密的过程可以分为两个阶段,分别是: 证书的认证阶段:使用非对称加解密算法对数据传送阶段的对称加解密密钥进行加密和解密。 数据传送阶段:通过证书认证阶段获取到目标服务器的对称加解密密钥,对数据进行加密传送给服务器。
加分回答
? HTTPS为了兼顾安全与效率,同时使用了对称加密和非对称加密。数据是被对称加密传输的,对称加密过程需要客户端的一个密钥,为了确保能把该密钥安全传输到服务器端,采用非对称加密对该密钥进行加密传输。总的来说,对数据进行对称加密,对称加密所要使用的密钥通过非对称加密传输。
在整个HTTPS数据传输的过程中一共会涉及到四个密钥:
CA机构的公钥,用来验证数字证书是否可信任 服务器端的公钥 服务器端的私钥 客户端生成的随机密钥
一个HTTPS请求可以分为两个阶段,证书认证阶段和数据传送阶段。又可以细分为六个步骤:
客户端第一次向服务器发起HTTPS请求,连接到服务器的443(默认)端口。 服务器端有一个密钥对,公钥和私钥。用来进行非对称加密使用,服务器端保存私钥,不能泄露,公钥可以发送给任何人。服务器将自己的数字证书(包含公钥)发送给客户端。 客户端收到服务器端的数字证书之后,会对数字证书进行检查,验证合法性。如果发现数字证书有问题,那么HTTPS传输就中断。如果数字证书合格,那么客户端生成一个随机值,这个随机值是数据传输阶段时给数据对称加密的密钥,然后用数字证书中的公钥加密这个随机值密钥,这样就生成了加密数据使用的密钥的密文。到这时,HTTPS中的第一次HTTP请求就结束了。 客户端第二次向服务器发起HTTP请求,将对称加密密钥的密文发送给服务器。 服务器接收到客户端发来的密文之后,通过使用非对称加密中的私钥解密密文,得到数据传送阶段使用的对称加密密钥。然后对需要返回给客户端的数据通过这个对称加密密钥加密,生成数据密文,最后将这个密文发送给客户端。 客户端收到服务器端发送过来的密文,通过本地密钥对密文进行解密,得到数据明文。到这时,HTTPS中的第二次HTTP请求结束,整个HTTPS传输完成。
HTTPS和HTTP的区别
1、HTTPS 协议需要到 CA (Certificate Authority,证书颁发机构)申请证书,一般免费证书较少,因而需要一定费用。(以前的网易官网是http,而网易邮箱是 https 。) 2、HTTP 是超文本传输协议,信息是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议。 3、HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。 4、HTTP 的连接很简单,是无状态的。HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。(无状态的意思是其数据包的发送、传输和接收都是相互独立的。无连接的意思是指通信双方都不长久的维持对方的任何信息。)
二、传输层
传输层主要有TCP协议和UDP协议
TCP协议
TCP(传输控制协议)是面向连接的、可靠传输的、字节流服务的协议。 字节流:通信双方的读写操作次数是否一致。当应用程序连续多次发送数据,TCP模块先将这些数据放入到发送缓冲区中,等到TCP模块真正发送数据的时候,将发送缓冲区的数据封装成一个TCP报文段或多个TCP报文段,所以应用程序写操作的次数和TCP模块发送的TCP报文段的个数没有固定关系。当应用程序的从接收缓冲区接收数据时,TCP模块将携带应用程序的数据按序号放入到接收缓冲区,应用程序可以一次性读取接收缓冲区的全部数据,也可以分多次读取,这取决于应用程序指定读取接收缓冲区的大小。所以应用程序的读取的次数和TCP模块接收TCP报文段的个数没有固定关系,这就是字节流的概念。 TCP传输为什么可靠的? 1、TCP协议采用发送应答机制。即发送端发送的每个TCP报文段都必须得到接收方的应答,才能确定TCP报文段的传输成功,保证了不丢包。 2、TCP协议采用超时重传机制。即发送端发送TCP报文段之后,会为该报文段开启定时器,当在定时器定时内没能接收到该报文段的应答后,它将重新发送该报文段。 3、TCP报文段的头部信息内含有序号,由于TCP报文段最后以IP数据报发送的,而IP数据报到达接收端可能是乱序的、重复的,故TCP协议会对接收到报文段按序重排、整理,再交付给应用层。 4、TCP协议有拥塞控制、流量控制机制。 5、TCP协议的顺序问题、丢包问题、流量控制都是通过滑动窗口来解决的。 6、拥塞控制通过拥塞窗口解决的。
TCP三次握手
TCP建立连接必须经过三次握手。过程如下: 第一次握手:客户端向服务端发起连接的请求,将标志位SYN=1,并随机生成一个值序列号为seq=x(SYN不携带任何数据,但需要消耗一个序列号),封装成TCP同步报文段发送到服务端,客户端进入了syn_sent状态。 第二次握手:服务端接收到同步报文段后,知道了客户端发起连接请求,故将标志位ACK=1,确认值ack=x+1,并随机生成一个值序列号seq=y,同时将标志位SYN=1,封装成TCP同步报文段(包含了确认值、新的序列号)发送给客户端,服务端进入了syn_rcvd状态。 第三次握手:客户端接收到了服务端的同步报文段后,然后将ACK=1,ack=y+1(ACK不携带任何数据,不消耗序列号),封装成TCP确认报文段发送到服务端,客户端进入了established状态。最后服务端接收到确认报文段后,也进入了established状态,完成了TCP连接的三次握手。 注意:建立连接之后,客户端第一次发送数据的序列号为x+1。 问题: 1、为什么要三次握手,两次握手可以吗? 原因: 1)TCP协议是可靠的、全双工的,意味着发送方发送一个TCP报文段后,都需要等待接收对方的确认应答,才能确定该报文段传输成功。TCP连接的三次握手,其实是发送方和接收方各自发送一次连接请求的同步报文段和一次确认对方的同步报文段操作。如果只有两次握手的话,那就意味着至少有一方的同步报文段没有得到确认,至多只有一方可以接收和发送的,TCP协议的可靠没有得到保证,故是不可以的。 2)防止无效的TCP报文段请求连接,导致资源的浪费。比如客户端第一次发送连接请求的同步报文段在某个网络结点长时间的滞留了,没有到达服务端,客户端重新发送后与服务端建立了连接,完成交互后关闭连接,这时滞留的TCP报文段发送到服务端,服务端就误认为是 客户端 再次发出的一个新的连接请求,而这时的客户端已关闭连接了,所以会导致无效连接情况,白白浪费了服务端的资源。 2、可以四次握手吗? 可以的。 有一种情况叫TCP同时打开,类似于自连接。 比如SYN_SENT状态下,又收到了一个SYN,其实就相当于自连接里,在发出了第一次握手后,又收到了第一次握手的请求。结果都是变成 SYN_RCVD。
在 SYN_RCVD 状态下收到了 SYN+ACK,就相当于自连接里,在发出第二次握手后,又收到第二次握手的请求,结果都是变成 ESTABLISHED。他们的源码其实都是同一块逻辑。
而且更重要的是,这里面只涉及两个客户端,没有服务端。 看到这里,不知道大家有没有跟我一样,被刷新了一波认知,对socket有了重新的认识。 在以前的观念里,建立连接,必须要有一个客户端和一个服务端,并且服务端还要执行一个listen()和一个accept()。而实际上,这些都不是必须的。 那么下次,面试官问你"没有listen(), TCP能建立连接吗?", 我想大家应该知道该怎么回答了。 另一种情况: 不过一般情况下,四次握手主要在第二次握手的时候分为两次握手。 1)服务端接收到客户端发送同步报文段后,会给客户端发送确认报文段ACK; 2)服务端会发起连接的请求,将同步报文段SYN发送到客户端; 但很明显没必要分为两次发送,可以将SYN和ACK结合一个TCP报文段发送,因为TCP的头部字段可以同时设置标志位SYN和ACK置为1。
TCP自连接
同一个客户端socket,自己对自己发起连接请求。是可以成功建立连接的。这样的连接,叫TCP自连接 特点:相同的socket,自己连自己的时候,握手是三次的。挥手是两次的。
TCP四次挥手
TCP关闭连接必须经过四次挥手。过程如下:一般情况下客户端主动关闭 第一次挥手:客户端发起FIN=1,sql=x结束报文段到服务端,用来关闭客户端到服务端的数据传送,客户端进入fin_wait_1状态。 第二次挥手:服务端接收到FIN结束报文段,然后发送一个ACK=1,seq=x+1的确认报文段到客户端,当客户端接收到确认报文段之后,客户端进入fin_wait_2状态。此时的连接处于半关闭状态,即客户端已经没有数据要发送给服务端,但服务端可能还有待发送的数据,等全部数据发送给客户端,客户端还可以接收。服务端进入close_wait状态。 第三次挥手:服务端发起FIN=1,seq=y的结束报文段,用来关闭服务端到客户端的数据传输,服务端进入了last_ack状态。 第四次挥手:客户端接收到了结束报文段,然后发送一个ACK=1,seq=y+1的确认报文段到服务端,客户端进入time_wait状态(没有立即进入closed状态)。服务端接收到了最后的确认报文段后,服务端进入了closed状态,完成了四次挥手。 问题: 1、为什么TCP挥手需要4次?三次挥手不行吗? 主要原因是当服务端收到客户端的 FIN 数据包后,服务端可能还有数据没发完,不会立即close。所以服务端会先将 ACK 发过去告诉客户端我收到你的断开请求了,但请再给我一点时间,这段时间用来发送剩下的数据报文,发完之后再将 FIN 包发给客户端表示现在可以断了。之后客户端需要收到 FIN 包后发送 ACK 确认断开信息给服务端,故这就是第二次挥手和第三次挥手分开的原因。 2、两次挥手? 前面在四次挥手中提到,关闭的时候双方都发出了一个FIN和收到了一个ACK。 正常情况下TCP连接的两端,是不同IP+端口的进程。 但如果TCP连接的两端,IP+端口是一样的情况下,那么在关闭连接的时候,也同样做到了一端发出了一个FIN,也收到了一个 ACK,只不过正好这两端其实是同一个socket 。 同一个socket确实可以自己连自己,形成一个连接。 3、为什么四次挥手释放连接时TIME_WAIT需要等待2MSL后? MSL:指TCP报文段在网络中最大生存时间。即TCP报文段在网络中传输的一个来回的时间,建议值为2分钟。 第一种情况:如果第四次挥手发送的确认报文段在传输过程中丢失,服务端等待接收不到最后的确认报文段,超时后会重传结束报文段给客户端,服务端最终等待接收到了确认报文段,这个过程的时间就是2MSL,保证了TCP连接的正确关闭。 另一种情况:如果没有time_wait状态的话,新的连接和刚刚关闭的连接IP和端口都一致的话,新的连接可能会收到迟到的报文段或网络中尚未被接收的报文段,这显然是错误的。故time_wait状态等待2MSL中,可以保证上一次连接的报文(迟到的报文段、尚未被接收到的报文段)已经在网络中消失,不会出现与新TCP连接报文冲突的情况。 TCP状态的详解: 链接:https://blog.csdn.net/qq_46495964/article/details/122761214?spm=1001.2014.3001.5501
流量控制
流量控制机制通过滑动窗口实现的。 滑动窗口: 1,保证数据的可靠传递 未确认的数据必须被发送方缓存起来 确认的数据将会移除缓冲区 2,保证数据的有序传输 乱序的数据必须被接收方缓存起来 3,提供End-to-End的流控机制 发送方发送太快就必须阻塞等待
流量控制:流量控制是为了控制发送方发送速率,保证接收方来得及接收。 TCP会话的双方都各自维护一个发送窗口和一个接收窗口。接收窗口大小取决于应用、系统、硬件的限制。发送窗口则取决于对端通告的接收窗口。接收方发送的确认报文中的window字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将接收方的确认报文window字段设置为 0,则发送方不能发送数据。
拥塞控制
拥塞:路由器因无法处理高速到达的流量而被迫丢弃数据信息的现象称为拥塞。 拥塞控制方法:慢开始( slow-start )、拥塞避免( congestion avoidance )、快重传( fast retransmit )和快恢复( fast recovery )。
慢开始 把拥塞窗口 cwnd 设置为一个最大报文段MSS的数值。而在每收到一个对新的报文段的确认后,把拥塞窗口增加至多一个MSS的数值。每经过一个传输轮次,拥塞窗口 cwnd 就加倍。 为了防止拥塞窗口cwnd增长过大引起网络拥塞,还需要设置一个慢开始门限ssthresh状态变量。
当 cwnd < ssthresh 时,使用慢开始算法。
当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法。
当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞控制避免算法。
拥塞避免 让拥塞窗口cwnd缓慢地增大,每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加1,而不是加倍。这样拥塞窗口cwnd按线性规律缓慢增长。
无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有收到确认),就要把慢开始门限ssthresh设置为出现拥塞时的发送 方窗口值的一半(但不能小于2)。然后把拥塞窗口cwnd重新设置为1,执行慢开始算法。这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生 拥塞的路由器有足够时间把队列中积压的分组处理完毕。
快重传 有时个别报文段会在网络中丢失,但实际上网络并未发生拥塞。如果发送方迟迟收不到确认,就会产生超时,就会误认为网络发生了拥塞。这就导致发送方错误地启动慢开始,把拥塞窗口cwnd又设置为1,因而降低了传输效率。
快重传算法可以避免这个问题。快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认,使发送方及早知道有报文段没有到达对方。
发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待重传计时器到期。由于发送方尽早重传未被确认的报文段,因此采用快重传后可以使整个网络吞吐量提高约20%。
快恢复 当发送方连续收到三个重复确认,就会把慢开始门限ssthresh减半,接着把cwnd值设置为慢开始门限ssthresh减半后的数值,然后开始执行拥塞避免算法,使拥塞窗口缓慢地线性增大。
在采用快恢复算法时,慢开始算法只是在TCP连接建立时和网络出现超时时才使用。 采用这样的拥塞控制方法使得TCP的性能有明显的改进。
UDP协议
UDP(User Datagram Protocol,用户数据报协议),是无连接的、提供不可靠的服务的传输层协议。 UDP特点:简单,轻量化、传输速度快。 UDP的缺点:没有流量控制、拥塞控制,没有应答确认机制,不能解决丢包、重发、错序问题。 TCP和UDP的区别: 1、UDP无连接:它不需要建立连接、不需要维护连接的状态,不跟踪连接参数;TCP需要三次握手建立连接,维护连接状态的参数(序号值、确认值、标志位、拥塞控制等参数)。故UDP在时间上、空间上相对于TCP开销较小。 2、UDP没有拥塞控制:应用层能够更好的控制要发送的数据和发送时间,网络中的拥塞也不会影响主机的发送速率。某些实时应用要求以稳定的速度发送,能容 忍一些数据的丢失,但是不能允许有较大的时延(比如实时视频,直播等);TCP有拥塞控制,避免TCP报文段在网络传输过程中出现网络拥塞时会导致报文段的丢失,采用慢开始、拥塞避免算法、快速重传、快速恢复保证了TCP报文段能顺利到达对端,但拥塞控制是有较大的延时的,也是UDP不可容忍的。 3、UDP提供最大的努力交付,不保证可靠传输:UDP的所有维护可靠传输的工作都需要用户在应用层完成,它没有TCP的发送应答确认机制、超时重传机制等来确保数据可靠传输。 4、UDP是面向报文的、不是字节流服务:对于接收应用层的数据加上UDP首部封装成数据报,直接完整交付到IP层,对于接收IP层的数据报,去除首部后原封不动地交付到应用层,报文不可分割,是用户数据报的接收最小单位。因为这样,UDP显得不够灵活,不能控制读写数据的次数和数量。比如我们要发送100个字节的报文,我们调用一次sendto函数就会发送100字节,对端也需要用recvfrom函数一次性接收100字节,不能使用循环每次获取10个字节,获取十次这样的做法。而TCP是以字节流方式进行传输的,用户的读写操作的次数和TCP模块发送/接收的次数没有固定的关系,TCP模块会对TCP报文段进行整合、切割操作。 5、UDP的首部8个字节,TCP首部20个字节。
UDP首部格式: UDP首部有8个字节,由4个字段构成,每个字段都是两个字节, 1.源端口: 源端口号,需要对方回信时选用,不需要时全部置0. 2.目的端口:目的端口号,在终点交付报文的时候需要用到。 3.长度:UDP的数据报的长度(包括首部和数据)其最小值为8(只有首部) 4.校验和:检测UDP数据报在传输中是否有错,有错则丢弃。 该字段是可选的,当源主机不想计算校验和,则直接令该字段全为0. 当传输层从IP层收到UDP数据报时,就根据首部中的目的端口,把UDP数据报通过相应的端口,上交给应用进程。 如果接收方UDP发现收到的报文中的目的端口号不正确(不存在对应端口号的应用进程0,),就丢弃该报文,并由ICMP发送“端口不可达”差错报文给对方。
总结
|