计算机网络

注:此文章的来源出处:小林coding --图解网络,此为我的读书笔记。

HTTP协议里的各类请求方法、URI/URL、状态码、头字段等每个组成要求都没有被固定死,都允许开发人员自定义和扩充,通过HTTP由于时工作在应用层,则它的下层可以随意变化。

HTTPS也就是在HTTP与TCP层之间增加了SSL/TLS安全传输层,HTTP/3甚至把TCP层换成了基于UDP的QUIC

3.应用广泛且跨平台

HTTP协议有优点,当然也有缺点,缺点就是【无状态、明文传输,同时还很不安全】

无状态的好处就是服务器不会记忆HTTP的状态,所以不需要额外的资源来记忆状态信息,这个能减轻服务器的压力,让更多的CPU和内存来提供对外的服务。

无状态的坏处及时,既然服务器没有记忆能力,那么在完成有关联性的操作时,会很麻烦。

对于无状态的问题,解决方案有很多种,其中比较简单的就是用Cookie技术

Cookie能通过在请求和响应的报文中,通过写入cookie信息来控制客户端的状态

相当于,在客户端第一次请求服务器资源后,服务器会下发一个装有客户信息的小纸条,后续客户端在请求服务器的时候

带上这个小纸条,服务器就能够认得了。

明文就意味着在传输过程中,是可方便阅读的,通过浏览器F12控制台或者Wireshark抓包,都可以肉眼查看,为我们的调试工作带来极大的便利,但是,正因如此,HTTP的所有信息都暴露在外,在传输的漫长过程中,信息的内容都毫无隐私,很容易被窃取,如果你的账号信息包含在内,那么对不起,你的号没了。

不安全

  • 通信使用明文,内容容易被监听,比如,账号信息容易泄露,你号没了;
  • 不验证通信方的身份,因此有可能遭到伪装,比如你去淘宝购物,你钱没了;
  • 无法证明报文的完整性,所以有可能已遭到篡改,比如网页植入垃圾广告,你眼没了;

HTTP的安全问题,可以用HTTPS的方式去解决,也就是通过引入SSL/TLS层,使得在安全上达到极致。

那你再说说HTTP/1.1的性能如何?

HTTP协议是基于TCP/IP的,并且使用了【请求-应答】的通信模式,所以性能的而关键就在这两点里:

早期的HTTP/1.0性能有很大的问题,那就是每发起一个请求,都要新建一次TCP连接,而且是串行请求,做了

无谓的TCP连接建立和断开,增加了性能的开销。

为了解决以上TCP的连接问题,HTTP/1.1提出了长连接的通信方式,也叫持久连接,这种方式的好处就在于减少了TCP

连接的重复断开和连接的过程,减轻服务器的负载。

持久连接的特点就是:只要任意一端没有明确的提出断开连接,那么就保持TCP连接状态。

2.管道网络传输

HTPP/1.1采用了长连接的方式,这使得管道网络传输成为了可能。

即可在同一个TCP连接里面,客户端可以发起多个请求,只要第一个请求发出去了,不必等其回来,就可以发第二次请求出去,可以减少整体的响应时间。

举个例子:如果客户端需要请求两个资源,以前的做法是,在同一个TCP连接里面,先发送A请求,之后等待服务器响应,收到后在发送B请求,而现在,客户端在发送A请求之后,不必等服务器响应就可以继续发送B请求。但是服务器还是

按照顺序,先回应A请求,完成之后再回应B请求。要是前面的回应特别满,后面就会有许多请求排队等待,这称为对

头堵塞。

队头阻塞

【请求-应答】的模式加剧了HTTP的性能问题

因为当顺序发送的请求序列中的一个请求因为某种原因而被堵塞后,之后的请求也会一同被堵塞,会导致客户端一直请求不到数据,这也就是队头堵塞,

总之HTTP/1.1的性能一般般,后续HTTP/2和HTTP/3都是再优化HTTP的性能、

HTTP与HTTPS有那些区别

  1. HTTP是超文本传输协议,信息是明文传输,存在安全风险问题,HTTPS则解决了HTTP的不安全的缺陷,在TCP和

    HTTP网络层之间加入了SSL/TLS安全协议,使得报文可以加密传输。

  2. HTTP连接建立相对简单,TCP三次握手之后便可以进行HTTP的报文传输,而HTTPS在TCP三次握手之后,还需要进行SSL/TLS的握手过程,才可以进入加密报文传输。

  3. HTTP的端口号是80,HTTPS的端口号是443

  4. HTTPS协议是需要向CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。

HTTPS解决了HTTP的那些问题?

  • 窃听风险,
  • 篡改风险
  • 冒充风险

信息加密:交换信息无法被窃取,

校验机制:无法篡改通信内容,篡改了就不能正常显示,

身份证书:

  • 混合加密的方式实现了信息的机密性,解决了窃听的风险;
  • 摘要算法的方式实现了完整性,他能够为数据生成独一无二的指纹,用于校验数据的完整性,解决篡改的风险;
  • 将服务器公钥放到数字证书中,解决了冒充的风险;

HTTPS采用的对称加密和非对称加密结合的混合加密方式:

  • 在通信建立之前采用非对称加密的方式交换【会话密钥】,后续就不再使用非对称加密;
  • 通过过程中,全部使用对称加密的会话密钥的方式加密明文数据;

采用混合加密的方式的原因:

  • 对称加密只使用一个密钥,运算速度快,密钥必须保密,无法做到安全的密钥交换;
  • 非对称加密使用两个密钥,公钥和私钥,公钥可以随意分发,而私钥保密,解决了密钥交换问题,但速度很慢

2.摘要算法

摘要算法是用来实现完整性,能够为数据生成独一无二的指纹,用于校验数据的完整性,解决了篡改的风险;

客户端在发送明文之前会通过摘要算法算出明文的指纹,发送的时候把指纹和明文一同加密成密文,发送给服务器后,服务器解密后,用相同的摘要算法算出发送过来的明文,通过比较客户端携带的指纹和当前算出的指纹,如果指纹相同,则说明数据是完整的。

3.数字证书

客户端先向服务器段索要公钥,然后用公钥加密信息,服务器收到密文之后,用自己的私钥解密;

这就存在问题,如何保证公钥不被篡改和信任度;

所以这就需要借助第三方权威机构CA(数字证书认证机构),将服务器的公钥放在数字证书中,只要证书是可性的,公钥就是可信的。

步骤:

  1. 服务器先把自己的公钥注册到CA;
  2. CA用自己的私钥将服务器的公钥数字签名并颁发数字证书;
  3. CA的公钥已事先置入到浏览器或操作系统里,
  4. 客户端拿到服务器的数字证书后,使用CA的公钥确认服务器的数字证书的真实性;
  5. 从数字证书获取到服务器的公钥之后,使用它对报文进行加密后发送
  6. 服务器用私钥对报文解密

通过数字证书的方式保证服务器公钥的可靠性,解决身份被冒充的风险;

HTTPS是如何建立连接的,其间交互了什么?

SSL/TLS协议的基本流程

  • 客户端向服务器索要并验证服务器的公钥;
  • 双方协商生产会话密钥;
  • 双方采用会话密钥进行加密通信

SSL/TLS的握手阶段设计到四次通信

SSL/TLS协议建立的详细流程:

1.ClientHello

首先,由客户端向服务器发起加密通信请求,也就是ClientHello请求;

在这一步,客户端主要向服务器发送一下信息:

(1)客户端支持的SSL/TLS协议版本,如TLS 1.2版本;

(2)客户端生产的随机数(Client Random),后面用于生产会话密钥;

(3)客户端支持的密码套件列表,如RSA加密算法

2.SeverHello

服务器收到客户端请求后,向客户端发出响应,也就是ServerHello,服务器回应的内容有:

(1)确认SSL/TLS协议版本,如果浏览器不支持,则关闭加密通信;

(2)服务器生产的随机数(Server Random)后面用于生产会话密钥;

(3)确认的密码套件列表;

(4)服务器的数字证书;

3.客户端回应

客户端在收到服务器的回应之后,首先通过浏览器或操作系统中的CA公钥,确认服务器的证书的真实性;

如果证书没有问题,客户端会从数字证书中取出服务器的公钥,然后使用它加密报文,向服务器发送如下信息:

(1)一个随机数,该随机数会被服务器公钥加密;

(2)加密通信算法改变通知,表示随后的信息都将用会话密钥加密通信;

(3)客户端握手结束通知,表示客户端的握手阶段已经结束,这一项同时把之前所有的内容发生的数据做个摘要,用来供服务器端校验;

上面第一项的随机数是整个握手阶段的第三个随机数,这样服务器和客户端就同时有三个随机数,接着用双方协商的加密算法,各自生成本次通信的会话密钥。

4.服务器的最后回应

服务器收到客户端的第三个随机数,通过协商的加密算法,计算出本次通信的会话密钥,然后,向客户端发出最后的信息:

(1)加密通信算法改变通知,表示随后的信息都将会用会话密钥加密通信;

(2)服务器握手结束通知,表示服务器的握手已经结束,这一项同时把之前所有内容所发生的数据做个摘要,提供客户端校验。

至此,整个SSL/TLS的握手阶段全部结束,接下来,客户端与服务器端进入加密通信,就完全是使用普通的HTTP协议,只不过用会话密钥加密内容。

HTTP/1.1 相比HTTP/1.0性能的改进:

  • 使用TCP长连接的方式改善了HTTP/1.0短连接的性能开销;
  • 使用管道网络传输,只要第一个请求发出去了,不必等起回来,就可以发第二次请求,可以减少整体的响应时间;

HTTP/1.1的性能瓶颈:

  • 请求、响应头未经压缩就发送,首部信息越多,延迟越大,只能压缩body部分
  • 发送冗长的首部,每次互相发送相同的首部造成的浪费较多;
  • 服务器是是按请求的顺序响应的,如果服务器响应慢,会导致客户端一直请求不到数据,也就是队头阻塞;
  • 没有请求优先级控制;
  • 请求只能从客户端开始,服务器只被动响应;

HTTP/2协议是基于HTTPS的,所以HTTP/2的安全性也是有保障的。

HTTP/2相比HTTP/1.1性能的改进:

1.头部压缩

HTTP/2会压缩头,如果你同时发出多个请求,他们的头是一样的或者是相似的,那么,协议会帮你消除重复的部分

这就是所谓的HPACK算法,在客户端和服务器同时维护一张头信息表,所有字段都会存入这张表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高了速度。

2.二进制格式

HTTP/2不再像HTTP/1.1里的纯文本形式的报文,而是全面采用了二进制格式,头信息和数据体都是二进制,并且统称为帧,头信息帧和数据帧

3.数据流

HTTP/2的数据包不是按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应,因此,必须要对数据包做标记,指出它属于那个回应;

每个请求或回应的所有数据包,称为一个数据流,每个流都标记着一个独一无二的编号,其中规定客户端发出的数据流编号为奇数,服务器发出的数据流编号为偶数。

客户端还可以指定数据流的优先级,优先级高的请求,服务器就先响应该请求。

4.多路复用

HTTP/2是可以在一个连接中并发多个请求或回应,而不用按照顺序一一对应。

移除了HTTP/1.1中的串行请求,不需要排队等待,也就不会在出现对头阻塞,降低了

延迟,大幅度提高了连接的利用率。

5.服务器推送

HTTP/2还在一定的程度上改善了传统的请求-应答的工作模式,服务器不再是被动的响应,也可以主动的向客户端发送消息,

HTTP/2的主要问题在于,多个HTTP请求在复用一个TCP连接,下层的TCP协议是不知道有多少个HTTP请求的,所以一旦发生丢包现象,就会触发TCP的重传机制,这样在一个TCP连接中的所有HTTP请求都必须等待这个丢了的包被重传回来。

  • HTTP/1.1中的管道传输中如果有一个请求阻塞了,那么队列后请求也统统被阻塞住了
  • HTTP/2多个请求复用一个TCP连接,一旦发生丢包,就会阻塞住所有的HTTP请求
  • 这都是基于TCP传输层的问题,所以HTTP/3把HTTP下层的TCP协议改成了UDP协议

基于UDP协议的QUIC协议可以实现类似TCP类似的TCP的可靠性传输

  • QUIC有自己的一套机制可以保证传输的可靠性,当某个流发生丢包的时候,只会阻塞这个流,其他流不会受到应i向影响;
  • TLS3升级为最新的TLS 1.3版本,头部压缩算法也升级为QPack;
  • HTTPS要建立一个连接,要花费6此交换,先是

序列号:在建立连接时由计算机生成的随机数作为其初始值,通过SYN包传给接收端主机,每发送一次数据,

就累加一次该数据字节数的大小,用于解决网络包乱序的问题。

确认应答号:指下一次期望收到的数据的序列号,发送端收到这个确认应答号以后可以认为在这个序号之前的数据都已经被正常接收,用来解决不丢包的问题。

控制位:

ACK:该位为1时,确认应答的字段变为有效,TCP规定除了最初建立连接的时候,SYN包之外该位必须设置为1

RST:该位为1时,表示TCP连接中出现异常,必须强制断开连接;

SYN:该位为1时,表示希望建立连接,并在其序列号的字段进行序列号初始值的设定;

FIN:该位为1时,表示今后不会再有数据发送,希望断开连接,当通信结束,希望断开的时候,通信的双方的主机之间既可以相互交换FIN位为1的TCP段;

为什么需要TCP协议,TCP工作在哪一层?

IP层是不可靠的,它不保证网络包的交互,不保证网络包的按序交付,也不保证网络包中的数据的完整性

如果需要保障网络数据包的可靠性,那么就需要由上层(传输层)的TCP协议来负责;

因为TCP是一个工作在传输层的可靠数据传输服务,他能确保接收端接收的网络包是无损坏、无间隔、非冗余按按序的

什么是TCP?

TCP是面向连接的,可靠的,基于字节流的传输层通信协议

面向连接:一定是一对一才能连接,不能像UDP协议可以一个主机同时向多个主机发送消息,也就是一对多无法做到的;

可靠的:无论网络链路中出现怎样的变化,TCP都可以保证一个报文一定能够到达接收端;

字节流:消息是没有边界的,所以无论我们消息有多大都可以传输,并且消息是有序的,当前一个消息没有收到的时候

即使它先收到了后面的字节,那么也不能仍给应用层去处理,同时对重复的报文会自动丢弃;

TCP协议简单来说,用于保证可靠性和流量控制维护的某些状态信息,这些信息的组合,包括Socket、序列号和窗口带下称为连接。所以我们可以知道,建立一个TCP连接是需要客户端与服务器端达成上述三个信息的共识;

  • Socket:由IP地址和端口号组成;
  • 序列号:用来解决乱序的问题;
  • 窗口大小:用来做流量控制

TCP四元组可以唯一的确定一个连接,四元组包括如下:

  • 源地址
  • 源端口
  • 目的地址
  • 目的端口

源地址和目的地址的字段(32)是在IP头部中,作用是通过IP协议发送报文给对方主机

源端口和目的端口的字段(16)是在TCP头部中,作用是告诉TCP协议应该把报文发给哪个进程;

有一个IP的服务器端监听了一个端口,他的TCP的最大连接数是多少?

服务器通常固定在某个本地端口上监听,等待客户端的连接请求,因此客户端IP和端口是可变的,其理论值计算公式如下:

最大的TCP连接数=客户端的IP数*客户端的端口数;

首先是文件描述符限制:Socket都是文件,所以首先要通过ulimit配置文件描述符的数目;

另一个是内存限制,每个TCP连接都要占用一定内存,操作系统的内存是有限的;

UDP不提供复杂的控制机制,利用IP提供面向无连接的通信服务;

UDP协议真的非常简单,头部只有8个字节,UDP的头部格式如下:

目标和源端口:主要告诉UDP协议应该把报文发给那个进程;

包长度:该字段保存了UDP首部的长度和数据的的长度之和

校验和:校验和是为了提供可靠的UDP首部和数据而设计的;

TCP与UDP的区别:

  1. 连接
    • TCP是面向连接的传输层协议,传输数据前要先建立连接;
    • UDP是不需要连接的,即可传输数据;
  2. 服务对象
    • TCP是一对一的两点服务,即一个连接只有两个端点;
    • UDP是支持一对一,一对多,多对多的交互通信;
  3. 可靠性
    • TCP是可靠交互数据的,数据可以无差错,不丢失,不重复,按序到达;
    • UDP是尽最大努力交付,不保证可靠交付数据;
  4. 拥塞控制、流量控制
    • TCP由拥塞控制和流量控制机制,保证数传输的安全性;
    • UDP则没有,即使网络非常堵塞,也不会影响UDP的发送效率
  5. 首部开销
    • TCP首部的长度比较长,会有一定的开销,首部在没有使用选项字段是20个自己,如果使用了选项,字段则会变长;
    • UDP首部只有8个自己,并且是固定不变的,开销较少;
  6. 传输方式
    • TCP是流式传输,没有边界,但保证顺序和可靠;
    • UDP是一个包一个包的发送,是由边界的,但可能会丢包和乱序;
  7. 分片不同
    • TCP的数据大小如果大于MSS大小,则会在传输层进行分片,目标主机收到后,也同样在传输层组装TCP数据包,如果中途丢失了一个分片,只需要传输丢失的分片;
    • UDP的数据大小如果大于MTU大小,则会在IP层进行分片,目标主机收到后,在IP层组装完数据,接着在传给传输层,但是如果中途丢失了一个分片,在实现可靠传输的UDP时,就需要重所有的数据包,这样传输效率就会很低,所以通常UDP的报文应该小于MTU;

TCP与UDP的应用场景:

由于TCP是面向连接的,能保证数据的可靠性交付,因此常用于:

FTP文件传输

HTTP/HTTPS

由于UDP面向无连接,它可以随时的发送数据,再加上UDP本身的处理既简单又高效,因此用于:

包总量较少的通信,如DNS、SNMP等

视频、音频等多媒体通信;

广播通信;

为什么UDP头部没有首部长度,而TCP头部有首部长度字段呢?

原因是TCP是有可变长的选项字段,而UDP的头部长度是固定的,无需多一个字段去记录UDP的首部长度。

为什么UDP头部有包长度字段而TCP头部则没有包长度字段?

TCP是这样计算负载数据的长度:

TCP数据的长度=IP长度-IP首部长度-TCP首部长度

其中IP总长度和IP首部长度,再IP首部格式是已知的,TCP首部长度,则是在TCP首部格式已知的,所以就可以得知TCP的数据长度。、

因为为了网络设备硬件设计和处理方便,首部长度需要时4字节的整数部,如果去掉了UDP包长度字段,那UDP首部长度就不是4字节的整数倍了,所以是为了补全,UDP首部长度是4字节的整数倍。

TCP连接建立

TCP是面向连接的协议,所以使用TCP前必须先建立连接,而建立连接时通过三次握手来进行的。

  • 一开始,客户端和服务器端都处于CLOSE状态,显示服务器主动监听某个端口,处理LISTEN状态;

  • 客户端会随机初始化序号,将此序号置于TCP首部的序号字段中,同时把SYN字段置1,表示SYN报文,接着把第一个SYN报文发送给服务器端,表示向服务器端发起连接,该报文不包含应用层数据,之后客户端处于SYN-SEND状态;

  • 服务器端收到客户端的SYN报文后,首先服务器已会随机初始化自己的序列号,并将序列号置于TCP首部的序号字段,同时把TCP首部的确认应答号填入client_isn+1,接着把SYN和ACK标志位置1,最后把报文发送给客户端,该报文也不包含应用层数据,之后服务器端处于SYN-REVD状态;

  • 客户端在收到服务器端报文之后,还要向服务器回应最后一个应答报文,首先该应答报文TCP首部ACK标志位1,其次确认应答号字段填入server_isn+1,最后把报文发送给服务器端,这次报文可以携带客户到服务器的数据,之后客户端处于ESTABLISHED状态;

  • 服务器在收到客户端的应答报文后,已进入ESTABLISHED状态;

    从上面的过程可以发现,第三次握手是可以携带数据的,前两次握手是不可以携带数据的。

    如何在Linux系统中查看TCP状态

    TCP的连接状态查看,在Linux可以通过netstat -napt命令查看

    为什么是三次握手,不是两次,四次?

    用于保证可靠性和流量控制维护的某些状态信息,这些信息的组合,包括Socket、序列号、窗口大小称为连接,

    所以,重要的是为什么三次握手才可以初始化Socket,序列号和窗口大小,并建立TCP连接。

    所以接下来以三个方面分析三次握手的原因:

    1. 三次握手才阻止组织重复历史连接的初始化(主要原因);
    2. 三次握手才可以同步双方的初始化序列号
    3. 三次握手才可以避免资源的浪费;

    原因一:

    简单来说,三次握手的首要原因就是为了防止旧的重复连接初始化导致混乱;

    客户端连续多次发送SYN建立连接的报文,在网络拥堵的情况下:

    一个旧的SYN报文,比新的SYN报文早到达了服务端;

    那么此时服务器端就会回一个SYN+ACK报文给客户端;

    客户端收到后,可以根据自身的上下文,判断这是一个历史连接,那么客户端就会发送RST报文给服务器端,表示终止这一次连接;

    如果是两次握手连接,就不能判定当前连接是否是历史连接,三次握手则可以在客户端准备发送第三次报文时,客户端有足够的上下文来判断当前的连接是否为历史连接;

    • 如果时历史连接,则第三次握手发送的报文时RST报文,以此中断历史连接;
    • 如果不是历史连接,则第三次握手发送的报文时是ACK报文,通信双方就会成功建立连接;

    所以,TCP使用三次握手建立连接的最主要的原因是防止历史连接初始化了连接;

    原因二:

    • 同步双方初始化序列号

    TCP协议的通信双方,都必须维护一个序列号,序列号是可靠性的一个关键因素,它的作用:

    • 接收方可以去除重复的数据;
    • 接收方可以更具数据包的序列号按序接收;
    • 可以标识发送出去的数据报,那些是已经被对方接收的;

    可见,序列号在TCP连接中占据着非常重要的作用,所以当客户端发送携带初始序列号的SYN报文的时候,需要服务器端回一个ACK应答报文,表示客户端的SYN报文已被服务器端成功接收,那当服务器端发送初始化序列号给客户端的时候,依然需要得到客户端的应答回应,这样一来一回,才能确报双方的初始序列号能被可靠的同步;

    原因三:

    如果只有两次握手,当客户端的SYN请求在网络中阻塞,客户端没有接收到ACK报文,就会重新发送SYN,由于没有第三次握手,服务器不清楚客户端是否收到自己发送的建立连接的ACK确认信号,所以每收到一个SYN就只能先主动建立一个连接,这回造成什么情况?

    如果客户端的SYN阻塞了,重复发送多次SYN报文,那么服务器在收到请求后,就会建立多个冗余的无效连接,造成不必要的资源浪费。

TCP建立连接的时候,通过三次握手能防止历史连接的建立,能减少不必要的资源开销,能帮助双方同步初始化序列哈后,序列号能够保证数据包不重复,不丢弃和按序传输。

不使用两次握手和四次握手的原因:

两次握手:无法防止历史连接的建立,会造成双方资源的浪费,也无法可靠的同步双方序列号;

四次握手:三次握手就理论上最少可靠连接建立,所以不需要使用更多 的通信次数

为什么客户端和服务器端的初始化序列号ISN是不相同的?

如果一个已经失效的连接被重用,但是该旧连接的历史报文还残留在网格中,如果序列号相同,那么就无法分辨出该报文是不是历史报文,如果历史报文被新的连接接收了,则会产生数据错乱。

所以每次建立连接前,重新初始化一个序列号主要是为了通信双方能够根据序号将不属于本连接的报文端丢弃

另一方面是为了安全性,防止黑客伪造相同的序列号的TCP报文对对方接收

初始化序列号ISN是如何随机产生的?

起始ISN是基于时钟的,每4毫秒+1,转一圈需要4.55个小时

ISN=M+F(localhost,localport,remotehost,remoteport)

MTU:一个网络包的最大长度,以太网一般为1500字节;

MSS:除去IP和TCP头部之后,一个网络包所能容纳的TCP数据的最大长度

为了达到最佳的传输效能TCP协议在建立连接的时候通常要协商双方的MSS,当TCP层发现,超过MSS时,则就会先进行分片,当然,由他形成的IP包的长度也就不会大于MTU,自然也就不用进行IP分片了。经过TCP层分片后,当一个TCP分片丢失后,进行重发也是以MSS为单位,而不用重传所有的分片,大大增加的重传的效率。

针对TCP应该如何编程

  • 服务器和客户端初始化socket,得到文件描述符;
  • 服务端调用bind,将绑定在IP地址和端口;
  • 服务端调用listen,进行监听;
  • 服务端调用accept,等待客户端连接;
  • 客户端调用connect,向服务器端的地址和端口发起请求;
  • 服务端accept返回用于传输的socket的文件描述符;
  • 客户端调用write写入数据;服务器端调用read读取数据;
  • 客户端断开连接时,会调用close,那么服务端read数据的时候,就会读取到EOF,待处理完数据后,服务端调用close,表示连接关闭;

这里需要注意的是:服务端调用accept时,连接成功了会返回一个已完成连接的socket,后续用来传输数据。所以,

监听的socket和真正用来传送的socket,是两个socket,一个叫做socket,一个叫做已完成连接的socket.

成功连接建立之后,双方开始通过read和write函数来读写数据,就向往一个文件流里面写东西一样;

listen时候参数backlog的意义?

Linux内核中会维护两个队列:

  • 未完成连接队列(SYN队列):接收到一个SYN建立连接的请求,处于SYN_RCVD状态;
  • 已完成连接队列(Accept队列):已完成TCP三次握手,处于ESTABLISHED状态;
int listen(int socketfd,int backlog)

参数一:socketfd为socketfd文件描述符

参数二:backlog,这参数在历史版本有一定的变化;

在早期Linux内核,backlog是SYN队列的大小,也就是未完成队列的大小;

在Linux内核2.2之后,backlog变成了accept队列,也就是已完成连接建立的队列长度,所以现在通常认为backlog是accept队列;

但是上限是内核参数somaxconn的大小,也就是accept队列的长度=min(backlog,somaxconn);

accept发生在三次握手的哪一步?

我们先看看客户端连接服务端的时候,发生了什么?

  • 客户端的协议栈向服务端发送了SYN包,并告诉服务端当前发送序列号client_isn,客户端进入SYN_SEND状态;

  • 服务器端的协议栈收到了这个包之后,和客户端进行了ACK应答,应答的值为client_isn+1,表示已接收SYN包,同时

    服务器也会发送一个SYN包,告诉客户端当前我的发送序列号为server_isn,服务器进入SYN_REVD状态;

  • 客户端协议栈在收到ACK之后,使得应用程序从connect调用返回,表示客户端到服务器端的单项连接建立成功,客户端的状态为ESTABLISHED,同时客户端协议栈也会对服务器端的SYN包进行应答,应答数据为server_isn+1;

  • 应答包到达服务器端后,服务器端协议栈使得accept阻塞调用返回,这个时候服务器端到客户端的单项连接也建立成功,服务器端也进入ESTABLISHED状态;

从上面的描述过程,我们可以得知connect成功返回是在第二次握手,服务器accept成功返回时在第三次握手成功之后。

客户端调用了close?连接断开的流程是什么?

  • 客户端调用了close,表面客户端没有数据需要发送了,则此时会向服务器发送FIN报文,进入FIN_WAIT_1状态;
  • 服务器接收到了FIN报文,TCP协议栈会为FIN包插入一个文件结束符EOF到缓冲区中,应用程序可以通过read调用来感知这个FIN包,这个EOF会被放在已排队等候的其他已接收的数据之后,这就意味着服务端需要处理这种异常情况,因为EOF表示在该连接上再无额外的数据到达,此时,服务器进入CLOSE_WAIT状态;
  • 接着,当处理 完数据之后,自然就会读取EOF,也是也调用close关闭他的套接字,这会使得服务端发出一个FIN包,之后,之后处于LAST_ACK状态;
  • 客户端接收到服务器端的FIN包,并发送ACK确认包给服务端,此时客户端进入了TIME_WAIT状态;
  • 服务器端收到ACK确认包之后,就进入了最后的CLOSE状态;
  • 客户端经过2MSL时间之后,也进入了CLOSE状态;

TCP是通过序列号,确认应答,重发控制,连接管理以及窗口控制等机制实现可靠性传输。

今天,将重点介绍TCP的重传机制,滑动窗口,流量控制,拥塞控制

重传机制:

  1. 超时重传;
  2. 快速重传;
  3. SACK
  4. D-SACK;

滑动窗口:

  1. 发送窗口;
  2. 接收窗口;

流量控制:

  1. 操作系统缓冲区于滑动窗口的关系;
  2. 窗口关闭;
  3. 糊涂窗口综合症;

拥塞控制:

  1. 慢启动;
  2. 拥塞控制;
  3. 拥塞发生;
  4. 快速回复;

重传机制:

TCP实现可靠传输的方式之一,就是通过序列号与确认应答;

在TCP中,当发送端的数据到达主机之后,接收主机会返回一个确认应答消息,表示已收到消息;

但是在错综复杂的网络,并不能如上图那么顺利能正常的数据传输,万一数据在传输过程中丢失了呢?

所以TCP针对数据丢包的情况,会用重传机制解决;

  • 超时重传;
  • 快速重传;
  • SACK;
  • D-SACK;

超时重传:

重传机制的其中一个方式,就是在发送数据的时候,设定一个定时器,当超过指定的时间之后,没有收到对方的ACK确认应答报文,就发重发该数据,也就是我们常说的超时重传;

TCP会在以下两种情况发生超时重传:

  • 数据包丢失;

  • 确认应答丢失;

我们先了解以下什么是RTT(Rount-Trip Time 往返时延),从下图我们可以知道:

RTT就是数据从网络一端传送到另一端所需的时间,也就是包的往返时间。

超时重传时间是以RTO(Retransmission Timeout 超时重传时间)表示;

假设在重传的情况下,超时时间RTO较长或较短会发生什么?

上图中有两种超时时间不同的情况:

  • 当超时时间,RTO较大时,重发就慢,丢了老半天才重发,没有效率,性能差;

  • 当超时时间,RTO较小的时候,会导致可能并没有丢失就重发了,于是重发的很快,会增加网络的拥堵,导致更多的超时,更多的超时导致更多的重发;

    精确的测试超时时间RTO的值时非常重要的,这个可以让我们的重传机制更高效;

    根据上述的两种情况,我们可以得知,超时重传时间RTO的值应该略大于报文往返RTT的值

至此,可能大家决定超时重传时间RTO值的计算,也不是很复杂;

好像就是发送端发包的时记下t0,让后接收端在把这个ACK回来时,再记一个t1,于是RTT=T1-T0,没那么简单,这只是一个采样,不能代表普遍的情况;

实际上报文往返RTT的值也是经常变化的,因为我们的网络也是时常变化的,也就因为报文往返RTT的值时经常波动变化的,所以超时重传时间RTO的值,应该是一个动态变化的值;

我们来看看Linux是如何计算RTO的呢?

估计往返时间,通常需要采用以下两个:

  • 需要TCP通过采样RTT的时间,然后进行加权平均,算出一个平滑RTT的值,而且这个值还是要不断变化的,因为网络状况也是不断的变化;
  • 除了采样RTT,还要采样RTT的波动范围,这样就可以避免如果RTT有一个大的波动的话,很难被发现情况;
SRTT = R1;
DevRTT = R1/2;
RTO=u*SRTT+a*DevRTT=u*R1+a*(R1/2);

后续计算RTO,其中R2为最新测量的RTT;
SRTT=SRTT+a(RTT-SRTT)=R1+a(R2-R1);
DevRTT=(1-b)*DevRTT+b*(|RTT-SRTT|)=(1-b)*(R1/2)+b*(|R2-R1|)
RTO=u*SRTT+a*DevRTT

其中SRTT是计算平滑的RTT,DevRTR是计算平滑的RTT与最新RTT的差距,

再Linux下,a=0.125,b=0.25,u=1,a=4

如果超时重发的数据,再次超时的时候,又需要重传的时候,TCP的策略是超时间隔加倍;

也就是每当遇到一次超时重传的时候,都会将下一次超时时间间隔设置为先前值的两倍,如果两次超时,则说明网络环境差,不宜频繁反复发送;

超时出发重传存在的问题就是,超时周期可能相对较长,那是不是可以有更快的方式呢?

也是就可以用快速重传机制来解决超时重发的时间等待;

还有一种实现重传机制的方式叫:sack

这种方式需要在TCP头部选项字段里加一个SACK的东西,它可以将缓存的地图发送给发送方,这样发送方就可以知道那那些数据收到了,那些数据没收到,知道了这些东西,就可以只重传丢失的数据;

如下图:发送方收到了三次同样的ACK确认报文,于是就会出发快速重发机制,通过SACK信息发现,只有200-299这段数据丢失,则重发的时候,就只选择这个TCP段进行重复;

如果要支持SACK,必须双方都要支持,在Linux下,可以通过net.ipv4.tcp_sack参数打开这个功能;

Duplicate SACK又称为D-SACK,其主要使用了SACK来告诉发送方,有哪些数据被重复接收了。

接收方发给发送方的两个ACK确认应答都

可见D-SACK有这个几个好处:

  1. 可以让发送方知道,是发出去的包丢了,还是接收方回应的ACK包丢了;
  2. 可以知道是不是发送方的数据包被网路延迟了;
  3. 可以知道网络种是不是把发送方的数据包给复制了;

在Linux下,可以通过net.ipv4.tcp_dsack参数开启/关闭这个功能;

滑动窗口

我们都知道TCP是每发送一个数据,都要进行一次确认应答,当上一个数据包收到应答,在发送下一个;

所以这样的传输方式有一个缺点:数据包的往返时间越长,通信的效率就越低;

为了解决这个问题,TCP引入了窗口这个概念,即使在往返时间较长的情况下,它也不会降低网络通信的效率;

那么有了窗口,就可以指定窗口的大小,窗口的大小就是指无需等待确认应答而可以继续发送数据的最大值;

窗口的实现实际上就是操作系统开辟的一个缓存空间,发送方主机在等待确认应答返回之前,必须在缓冲区中保留已发送的数据,如果按期收到确认应答,此时数据就可以从缓冲区清除;

假设窗口大小为3个TCP段,那么发送发就可以连续发送3个TCP段,并且终于若有ACK丢失,可以通过下一个确认应答进行确认,如下图:

图中的ACK 600确认应答报文丢失,也没关系,因为可以通过下一个确认应答进行确认,只要发送方收到了ACK700确认应带,就意味着700之前的所有数据接收方都收到了,这个模式就叫累计确认,或者累计应答;

窗口大小由哪一方决定?

TCP头里面有一个字段叫Window,也就是窗口的大小

这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据,于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来了。

IP的作用是在复杂的网络的网络环境中将数据包发送给目的主机

A 0.0.0.0 ~ 127.255.255.255 16777214

B 128.0.0.0 ~ 191.255.255.255 65534

C 192.0.0.0 ~ 223.255.255.255 254

在IP地址中,由两个IP是特殊的,分别是主机号全为1和全为0的地址;

主机号全为1指定某个网络下的所有主机,用于广播;

主机号全为0指定某个网络;

广播地址用于什么?

广播地址用于在同一个链路中相互连接的主机之间发送数据包;

广播地址可以分为本地广播和直接广播两种,

在本网络内广播的叫做本地广播,因为这个广播地址的IP包会被路由器屏蔽,

在不同网络之间的广播叫做直接广播,

IP分类地址的优点:简单明了,选路简单;

缺点:

  1. 同一网络下没有地址层次;
  2. 不能很好的与现实网络匹配;

无分类地址CIDR

正因为IP分类由许多缺点,所以后面提出了无分类地址的方案,即CIDR;

这种方式不再有分类地址的概念,32比特的IP地址划分为两部分,前面是网络号,后面是主机号;

还有另外一种划分网络号和主机号的形式,那就是子网掩码

将子网掩码和IP地址按位计算AND,就可以得到网络号

因为两台计算机要通讯,首先要判断是否处于同一个广播域内,如果网络地址相同,表面接收方在本网络上,那么可以把数据包直接发送给对方的主机

路由器寻址工作中,也就是通过这样的方式来找到对应的网络号的,进而把数据包转发给对应的网络内。

如何进行子网的划分;

在上面我们可以知道通过子网掩码划分出网络号和主机号,那实际上子网掩码还有一个作用,那就是划分子网;

子网划分实际上是将主机地址分为两个部分:子网网络地和子网主机地址;形式如下:

192.168.1.0

255.255.255.192

1 2 4 8 16 32 64 128

公有IP地址和私有IP地址

私有IP地址通常是由内部的IT人员管理,公有IP地址是由ICANN组织管理,中文叫互联网名称与数字地址分配机构。

IP地址与路由控制

IP地址的网络地址这一部分是用于进行路由控制;

路由控制表记录着网络地址与下一步应该发送至路由器的地址,在主机和路由器上都会有各自的路由控制表;

在发送IP包时,首先要确定IP包首部的目标地址,再从路由控制表中找到与该地址具有相同网络地址的记录,根据该记录,将IP包转发给相应的下一个路由器,如果路由控制表存在多条相同的网络地址的记录,就选则相同位数最多的网络地址,也就是最长匹配;

  1. 主机A要发送一个IP包,其源地址为10.1.1.30和目标地址为10.1.2.10,由于没有在主机A的路由表找到与该目标地址10.1.2.10的网络地址,于是包就被转发到默认路由器1上;
  2. 路由器1收到IP包后,也在路由器1的路由表匹配到与目标相同的网络地址记录,发现匹配到了,于是就把IP数据包转发到了10.1.0.2这台路由器2
  3. 路由器2收到后,同样对比自身的路由表,发现匹配到了,于是把IP包从路由器2的10.1.2.1这个接口出去,最终经过交换机把IP数据包转发到目标主机。

每种数据链路的最大传输单元MTU都是不相同的,如FDDI数据链路MTU 4352

每种数据链路的MTU之所以不同,是因为每个不同类型的数据链路使用的目的不同,
使用目的不同,可承载的MTU也就不同

当IP数据包大于MTU时,数据包就会被分片,经过分片的IP数据被重组的时候,只能由目标主机进行,

路由器时不会进行重组的

在分片传输中,一旦某个分片丢失,则会造成整个IP数据报作废,所以TCP引入了MSS也就是TCP层进行分片,不用IP层进行分片,那么对于UDP,我们尽量不用发送一个大于MTU的数据报文。

IPv6可以自动配置,即使没有DHCP服务器也可以实现自动分配IP地址,真是便捷到即插即用;

IPv4包头部包首部长度采用了固定值40字节,去掉了包头校验和,简化了首部结构,减轻了路由器负荷,大大提供了传输的性能。

1. DNS域名解析;
2. ARP与RAPR协议;
3. DHCP动态获取IP地址;
4. NAT网络地址转换;
5. ICMP互联网控制报文协议;
6. IGMP因特网组管理协议;

DNS:可以将域名自动转化为具体的IP地址;
DNS中的域名都是用句点分隔的,比如。www.baidu.com ,这里的句点代表了不同层次之间的界限。
在域名中,越靠右的位置表示其层次越高。
毕竟域名是外国人发明,所以思维和中国人相反,比如说一个城市地点的时候,外国人喜欢从下到大的方式顺序说起,

根域是在最顶层,他的下一层就是com顶级域,再下面是server.com
所以域名的层级关系类似一个树状结构:
1. 根DNS服务器;
2. 顶级域DNS服务器;
3. 权威DNS服务器;
根域的DNS服务器信息保存在互联网中的所有DNS服务器,这样一来,任何DNS服务器就都可以找到根域DNS服务器;
域名解析的工作流程:
浏览器首先看一下自己的缓存里有没有,如果没有,就向操作
在传输一个IP数据报的时候,确定了源IP地址和目标IP地址之后,就会通过主机的路由表,确定IP数据包下一跳,然而,网络层的下一层是数据链路层,所以我们还有知道下一跳的MAC地址;
由于主机的路由表中可以找到下一条的IP地址,所以可以通过ARP协议,求的下一跳的MAC地址;
ARP是借助ARP请求和ARP响应两种类型的包确定MAC地址;;
主机会通过广播发送ARP请求,这个包包含了想要知道的MAC地址的主机IP地址;
当同个链路中的所有设备收到ARP请求的时候,都会去拆开ARP请求包里的内容,如果ARP请求包中的目标地址与自己的IP地址一致,那么这个设备就会将自己的MAP地址塞入APR响应包返回主机;
操作系统通常会把第一次通过ARP获取的MAC地址缓存起来,以便一次直接从缓存中找到对应的IP的MAC地址

不过,MAC地址的缓存是有一定期限的,超过这个期限,缓存的内容将会被清除;
RARP协议你知道是什么吗?
ARP协议是已知IP地址求MAC地址,那么RARP协议是正好相反,它是一直MAC地址,求IP地址,例如将打印机服务器等小型嵌入式设备接入到网络的时候就经常用到;
通常这需要假设一台RARP服务器,在这个服务器上注册设备的MAC地址及其IP地址,然后再将这个设备接入网路,接着,该设备就会发送一条[我的MAC地址是XXXX,请告诉我,我的IP地址应该是什么]的请求信息;
后续,RARP服务器接到这个消息后返回MAC地址为XXXX的设备,IP地址为XXXX的信息给这个设备
最后,设备就根据从RARP服务器所收到的应答消息设置自己的IP地址;

DHCP
DHCP在生活中我们是很常见的了,我们的电脑通常都是通过DHCP动态获取IP地址,大大的省去了繁琐的过程;
先说明一点,DHCP客户端进程监听的是68端口号,DHCP服务端进程监听的是67端口;
步骤如下:
1. 客户端首先发起DHCP发现报文(DHCP DISCOVER)的IP数据包),由于客户端没有IP地址,也就是不知道DHCP服务器的地址,所以使用的UDP广播通信,其使用的广播通信,其使用的广播地址是255.255.255.255(端口67),并且使用0.0.0.0(端口)作为源IP地址,DHCP客户端将IP数据包传递给链路层,链路层然后将帧广播到所有的网络中设备;
DHCP服务器收到DHCP发现报文的时候,用DHCP提供报文(DHCP OFFER)像客户端做出响应,该报文仍然使用IP广播地址255.255.255.255,该报文信息携带服务器提供可租约的IP地址,子网掩码,默认网关,以及DNS服务器和IP地址租用期

客户端收到一个或多个服务器的DHCP提供报文之后,从中选择一个服务器,并向选中的服务器发送DHCP请求报文进行响应,回显配置的参数。

网络地址转换NAT的方法?再次缓解了IPv4地址耗尽的问题?
由于绝大数的网络应用都使用传输层协议TCP或UDP来传输数据的,因此,可以把IP地址+端口号一起转换
这样一个全球IP地址就可以了,这种转换技术就叫做网络地址与端口转换NAPT


由于NAT/NAPT都依赖自己的转换表,因此会有以下的问题:
1. 外部无法主动与NAT内部服务器建立连接,因为NAPT转换表没有转换记录;
2. 转换表的生成与转换操作都会产能性能开销;
3. 通信过程中,如果NAT路由器重启了,所有的TCP连接都将被重置;
ICMP全称是Internet Control Message protocol 也就是互联网控制报文协议
ICMP主要的功能包括:确认IP包是否成功送达目标地址,报告发送过程中IP包被丢弃的原因和改善网络设置

在IP通信中,如果某个IP包因为某种原因未能到达,那么这个具体的原因将由ICMP负责通知;
ICMP这种通知消息会使用IP进行发送;
ICMP报文是封装到IP包里面的,它工作在网络层,是IP协议的助手;

一类用于诊断的查询消息,也就是查询报文类型;
一类是通知出错原因的错误消息,也就是差错报文类型

回送消息  --类型0和8
回送消息用于进行通知的主机或路由器之间,判断所发送的数据报是否成功到达对端的一种消息,ping命令就是利用这个消息实现的;

注:此文章的来源出处:小林coding --图解网络,此为我的读书笔记。



















I









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值