1. C++
2. 计算机网络
3. 操作系统
4. 数据库
5. 数据结构
6. 杂项
零、总述
1. OSI7层协议
物理层:RJ45、CLOCK、IEEE802.3(中继器,集线器)
链路层:PPP、FR、HDLC、VLAN、MAC(网桥,交换机)
网络层:IP、ICMP、DHCP、NAT、ARP、RARP、OSPF、IPX、RIP、IGRP、(路由器)
传输层:TCP、UDP、SPX
会话层:NFS、SQL、NETBIOS、RPC(提供了数据交换的同步、定界、建立检查点和恢复能力)
表示层:JPEG、MPEG、ASII(加密解密压缩解压数据,对数据格式进行编译将二进制转换成我们能够识别的数据)
应用层:FTP、DNS(基于UDP)、Telnet、SMTP、HTTP、WWW、NFS
分层原因
网络分层的原则: 每一层独立于其它层完成自己的工作,而不需要相互依赖,上下层之间通 过标准结构来互相通信,简单易用又具有拓展性。复杂的系统需要分层,因为每一层都需要专注于一类事情。我们的网络分层的原因也是一 样,每一层只专注于做一类事情。
各层之间相互独立:各层之间相互独立,各层之间不需要关心其他层是如何实现的,只需要知道自己如何调用下层提供好的功能就可以了(可以简单理解为接口调用)。这个 和我们对开发时系统进行分层是一个道理。
提高了整体灵活性 :每一层都可以使用最适合的技术来实现,你只需要保证你提供的功能以及暴露的接口的规则没有改变就行了。这个和我们平时开发系统的时候要求的高内 聚、低耦合的原则也是可以对应上的。
大问题化小 :分层可以将复杂的网络间题分解为许多比较小的、界线比较清晰简单的小问题来处理和解决。这样使得复杂的计算机网络系统变得易于设计,实现和标准化。这 个和我们平时开发的时候,一般会将系统功能分解,然后将复杂的问题分解为容易理解 的更小的问题是相对应的,这些较小的问题具有更好的边界(目标和接口)定义。
2. 4种分组时延
处理时延 排队时延 传输时延 传播时延
一、应用层
1. 网页请求过程
(0)DHCP服务器给主机分配IP地址(目的IP地址FFFFFFFF)
(1)DNS解析,获取IP地址;(ARP(获取路由器MAC地址))
(路由器选路RIP OSPF BGP)
(2)建立TCP连接,3次握手;
(3)发送HTTP请求报文;
(4)服务器接收请求并作处理;
(5)服务器发送HTTP响应报文;
(6)断开TCP连接,4次挥手。
- (DHCP过程详解)
(1) 发现阶段:即DHCP客户端寻找DHCP服务器的阶段。
(2) 提供阶段:即DHCP服务器提供IP地址的阶段。
(3) 选择阶段:即DHCP客户端选择某台DHCP服务器提供的IP地址的阶段。
(4) 确认阶段:即DHCP服务器确认所提供的IP地址的阶段 - 操作系统生成一个DNS查询报文,放到UDP报文段中(53号端口),再封装成IP数据报,放入一个以太网帧中,发送到DNS服务器中(发送到网关路由器)。中间可能涉及要查询网关路由器的MAC地址,需要使用ARP协议,ARP协议先用广播的方式发送,网关路由器接收到目标IP与自己的端口吻合,会单播方式发送ARP回答给他。获取了网关路由器的MAC地址后,可以往官网路由器中发送DNS查询报文,让路由器发送给DNS服务器。到了DNS服务器后,找到了URL对应的IP地址,然后发送会给我的电脑,我的电脑就有了目标IP了,这时可以生成TCP套接字,用于发送HTTP 。要进行TCP的三次握手,端口号为80,服务器收到HTTP报文后,生成一个HTTP响应报文,将请求的内容放进去,发回我的电脑里面,我的浏览器重套接字中读取到HTTP响应,从中抽取web网页的html,然后显示web网页。完成浏览后,将断开TCP连接,4次挥手。
2. FTP协议
文件传输协议,FTP协议在工作时使用两个并行的TCP连接,一个是控制连接(21),一个是数据连接(20),控制连接用来传输控制信息,如连接请求,传送请求,会在整个会话期间一直保持打开状态。数据连接用来连接客户端和服务端的数据传送进程,完成实际的文件传送,在传送完毕后会关闭。
3. http/https
Http协议运行在TCP之上,明文传输,客户端与服务器端都无法验证对方的身份;Https是身披SSL(Secure Socket Layer)外壳的Http,运行于SSL上,SSL运行于TCP之上,是添加了加密和认证机制的HTTP。二者之间存在如下不同:
端口不同:Http与Http使用不同的连接方式,用的端口也不一样,前者是80,后者是443;
资源消耗:和HTTP通信相比,Https通信会由于加减密处理消耗更多的CPU和内存资源;
开销:Https通信需要证书,而证书一般需要向认证机构购买;
Https的加密机制是一种共享密钥加密和公开密钥加密并用的混合加密机制。
HTTPS就是HTTP加上SSL加密处理(一般是SSL安全通信线路)+认证+完整性保护
使用了对称加密和非对称加密。数据是被对称加密传输的,对称加密过程需要客户端的一个密钥,为了确保能把该密钥安全传输到服务器端,采用非对称加密对该密钥进行加密传输,总的来说,对数据进行对称加密,对称加密所要使用的密钥通过非对称加密传输。
① 证书验证阶段
(1)客户端向服务器发起HTTPS请求,连接到服务器的443端口
(2)服务器端有一个密钥对,即公钥和私钥,是用来进行非对称加密使用的,服务器端保存着私钥,不能将其泄露,公钥可以发送给任何人。
(3)服务器将自己的公钥发送给客户端。其实是发证书,证书是CA颁发的。(证书=公钥+申请者与颁发者信息+签名)
(4)客户端收到服务器端的证书之后,会对证书进行检查,验证其合法性,如果发现证书有问题,那么HTTPS传输就无法继续。
首先浏览器会从内置的证书列表中索引,没找到就查找是否为权威机构颁发,并取出该机构颁发的公钥。用机构的证书公钥解密得到证书的内容和证书签名,内容包括网站的网址、网站的公钥、证书的有效期等。浏览器会先验证证书签名的合法性。然后浏览器验证证书记录的网址是否和当前网址是一致的。如果网址一致会检查证书有效期。这些都通过认证时,浏览器就可以安全使用证书中的网站公钥了。
客户端会生成一个随机值,这个随机值就是用于进行对称加密的密钥,即客户端密钥。然后用服务器的公钥对客户端密钥进行非对称加密,这样客户端密钥就变成密文了,至此,HTTPS中的第一次HTTP请求结束。
② 数据传输阶段
(1)客户端会发起HTTPS中的第二个HTTP请求,将加密之后的客户端密钥发送给服务器。
(2)服务器接收到客户端发来的密文之后,会用自己的私钥对其进行非对称解密,解密之后的明文就是客户端密钥,然后用客户端密钥对数据进行对称加密,这样数据就变成了密文。
(3)然后服务器将加密后的密文发送给客户端
(4)客户端收到服务器发送来的密文,用客户端密钥对其进行对称解密,得到服务器发送的数据。这样HTTPS中的第二个HTTP请求结束,整个HTTPS传输完成。
对称加密:加密和解密使用同一个密钥。
优点:算法公开,计算量小,加密速度快,加密效率高
缺点:双方使用相同的钥匙,安全性得不到保证,双方要维护大量的密钥,维护成本大
非对称加密:
非对称加密算法需要两个密钥:公开密钥(publickey) 和私有密(privatekey)
公开密钥和私有密钥是一对,加密和解密花费时间长、速度慢
如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密。
如果用私有密钥对数据进行加密,只有用对应的公开密钥才能解密。
HTTP1.0/HTTP1.1/HTTP2.0
- http/1. 0 :
- 默认不支持长连接,需要设置keep:-alive参数指定
- 强缓存expired 、协商缓存last-modi ed\if-modi ed-since 有一定的缺陷
- http 1. 1 :
- 默认长连接 (Keep-alwe) http请求可以复用Tep连接,但是同一时间只能对应一个http请求 (http请求在一个Tep中是串行的)
- 增加了强缓存cache-control 、协商缓存etag\if-none-match 是对http/1 缓存的优化
- http/2.0:
- 多路复用,一个Tep中多个http请求是并行的(雪碧图、多域名散列等优化手段http/2 中将变得多余)
- 二进制格式编码传输
- 使用HPACK算法做header压缩
- 服务端推送
HTTP2.0
HTTP(超文本传输协议)是一个无状态的、应用层的协议,常基于TCP的连接方式,HTTP1.1版本中给出一种持续连接的机制,绝大多数的Web开发,都是构建在HTTP协议之上的Web应用。
HTTP有两种报文:请求报文和响应报文
- 请求报文
HTTP请求报文主要包括请求行、请求头部以及请求的数据(实体) 三部分。
- 请求行(HTTP请求报文的第一行)请求行由方法字段、URL字段和HTTP协议版本字段。其中,方法字段严格区分大小写,当前HTTP协议中的方法都是大写,方法字段如下介绍如下:
- 请求头部:位于请求行的下面, 是一个个的key-value值
- 空行(CR+LF):请求报文用空行表示header和请求数据的分隔
- 请求数据**:GET方法没有携带数据, POST方法会携带一个body,请求内容放在body中
- 响应报文
HTTP的响应报文包括:状态行,响应头部,相应的数据(响应体)
- 状态行包括:HTTP版本号,状态码和状态值组成。响应头类似请求头,是一系列key-value值
- 空白行:同上,响应报文也用空白行来分隔header和数据 响应体:响应的数据
常用方法:
GET:用于请求访问已经被URI识别的资源,可以通过URL传参给服务器。
POST:用于传输信息给服务器,主要功能与GET方法类似,但一般推荐使用POST方式。
PUT: 传输文件,报文主体中包含文件内容,保存到对应URI位置。
HEAD: 获得报文首部,与GET方法类似,但不返回报文主体,用于验证URI是否有效。
DELETE:删除文件,与PUT方法相反,删除对应URI位置的文件。
OPTIONS:查询相应URI支持的HTTP方法。
Get与post的不同(详解):
- 报文提交
**GET提交:**请求的数据会附在URL之后(就是把数据放置在HTTP协议头<request-line>中),以?分割URL和传输数据,多个参数用&连接;例如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0 %E5%A5%BD。如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密,得出如: %E4%BD%A0%E5%A5%BD,其中%XX中的XX为该符号以16进制表示的ASCII。
**POST提交:**把提交的数据放置在是HTTP包的包体<request-body>中。上文示例中红色字体标明的就是实际的传输数据
因此,GET提交的数据会在地址栏中显示出来,而POST提交,地址栏不会改变 - 传输数据的大小:
HTTP协议没有对传输的数据大小进行限制,HTTP协议规范也没有对URL长度进行限制。 而在实际开发中存在的限制主要有:
**GET:**特定浏览器和服务器对URL长度有限制,例如IE对URL长度的限制是2083字节(2K+35)。对于其他浏览器,如Netscape、FireFox等,理论上没有长度限制,其限制取决于操作系统的支持。
因此对于GET提交时,传输数据就会受到URL长度的限制。
**POST:**由于不是通过URL传值,理论上数据不受限。但实际各个WEB服务器会规定对post提交数据大小进行限制,Apache、IIS6都有各自的配置。 - 安全性:
POST的安全性要比GET的安全性高。注意:这里所说的安全性和上面GET提到的“安全”不是同个概念。上面“安全”的含义仅仅是不作数据修改,而这里安全的含义是真正的Security的含义,比如:通过GET提交数据,用户名和密码将明文出现在URL上,因为(1)登录页面有可能被浏览器缓存, (2)其他人查看浏览器的历史纪录,那么别人就可以拿到你的账号和密码了 - 应用:
get能被缓存,可收藏为书签,post不行(书签仅包括URL,所有的形式参数都将丢失)。
精简回答
- 最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数。
- get能被缓存,可收藏为书签,post不行(书签仅包括URL,所有的形式参数都将丢失)。
- get受url的长度限制(2048个字符),post没有,所以传文件用post
- get不安全,能被看到,post安全
常见状态码:
1×× : 请求处理中,请求已被接受,正在处理
2×× : 请求成功,请求被成功处理
200 OK
3×× : 重定向,要完成请求必须进行进一步处理
301 : 永久性转移
302 :暂时性转移
304 : 已缓存
4×× : 客户端错误,请求不合法
400:Bad Request,请求有语法问题
403:拒绝请求
404:客户端所访问的页面不存在
5×× : 服务器端错误,服务器不能处理合法请求
500 :服务器内部错误
503 : 服务不可用,稍等
邮件相关协议
SMTP:持续连接,7比特ASCII编码格式,所有文件打包到一个报文中
4. DNS查询
根DNS服务器-顶级域服务器-权威DNS服务器-本地DNS服务器
先看本地的DNS缓存中有没有,如果有的话,就直接用本地缓存的。如果没有,那么就存在两种方式,递归和非递归方式,
1.迭代查询:查一次返回一次
一般客户机和服务器之间属递归查询,即当客户机向DNS服务器发出请求后,若DNS服务器本身不能解析,则会向另外的DNS服务器发出查询请求,得到结果后转交给客户机;
2.递归查询:一直查询下去,最后返回
一般DNS服务器之间属迭代查询,如:若DNS2不能响应DNS1的请求,则它会将DNS3的IP给DNS2,以便其再向DNS3发出请求;
5. WEB站点使用Cookie的目的
限制用户的访问
把内容和用户身份关联起来
Cookie技术的组成部分:
在HTTP响应报文中有一个Cookie首部行
在HTTP请求报文中也有一个Cookie首部行
在用户的端系统中保留了一个Cookie文件,由用户浏览器负责管理
在Web站点有一个后端数据库
Cookie Session 的关系和区别(详解)
- Cookie Session都是会话的一种方式。它们的典型使用场呆比如“购物车”,当你点击下单按钮时,服务端并不清楚具体用户的具体操作,为了标识并跟踪该用户,了解购物车中有几样物品,服务端通过为该用户创建Cookie/Session来获取这些信息。
- cookie数据存放在客户的浏览器上, session数据放在服务器上。
- cooki 不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session
- session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用COOKIE
- 单个cookie 保存的数据不能超过4K, 很多浏览器都限制一个站点最多保存20 cookie
客户端浏览器将 Cookie 功能禁用,或者不支持 Cookie 怎么办(详解)?
- 一般这种情况下,会使用一种叫做 URL 重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。
- 还有一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器
会话cookie和持久cookie
- 会话cookie:
如果 cookie 不包含到期日期,则可视为会话 cookie。 是一种临时的cookie,它记录了用户访问站点时的设置和偏好,关闭浏览器,会话cookie就被删除了,但是对应的session并没有从服务器上删除,只是无法使用,过期或者服务被自动清除。 - 持久化cookie:
如果 cookie 包含到期日期,则可视为持久性 cookie。 存储在硬盘上,不同的操作系统,不同的浏览器存储的位置不一样,不管浏览器退出,或电脑重启,持久cookie都存在。持久cookie有过期时间。
二、运输层
1. TCP和UDP区别 什么是IOCP?
1.TCP面向连接, UDP面向无连接的
2.TCP有保障的,UDP传输无保障的
3.TCP是效率低的,UDP效率高的
4.TCP是基于流的,UDP基于数据报文
5.TCP传输重要数据,UDP传输不重要的数据
6.TCP对系统资源要求较多,UDP对系统资源要求较少
IOCP
IOCP全称I/O Completion Port,中文译为I/O完成端口。
IOCP是一个异步I/O的API,它可以高效地将I/O事件通知给应用程序。
与使用select()或是其它异步方法不同的是,一个套接字[socket]与一个完成端口关联了起来,然后就可继续进行正常的Winsock操作了。然而,当一个事件发生的时候,此完成端口就将被操作系统加入一个队列中。然后应用程序可以对核心层进行查询以得到此完成端口。
IOCP和Epoll之间的异同。
异:
- IOCP是Windows系统下使用。Epoll是Linux系统下使用。
- IOCP是IO操作完毕之后,通过Get函数获得一个完成的事件通知。Epoll是当你希望进行一个IO操作时,向Epoll查询是否可读或者可写,若处于可读或可写状态后,Epoll会通过epoll_wait进行通知。
- IOCP封装了异步的消息事件的通知机制,同时封装了部分IO操作。但Epoll仅仅封装了一个异步事件的通知机制,并不负责IO读写操作。Epoll保持了事件通知和IO操作间的独立性,更加简单灵活。
- 从应用程序的角度来看, Epoll是同步非阻塞的;IOCP是异步操作;
同: - 它们都是异步的事件驱动的网络模型。
- 它们都可以向底层进行指针数据传递,当返回事件时,除可通知事件类型外,还可以通知事件相关数据。
2. 三次握手和四次挥手
(1). 三次握手(我要和你建立链接,你真的要和我建立链接么,我真的要和你建立链接,成功):
第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。
注:前两次握手SYN位位1,不允许携带数据,第三次握手SYN位0,可以携带数据。
(2). 四次挥手(我要和你断开链接;好的,断吧。我也要和你断开链接;好的,断吧):
第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。此时TCP链接处于半关闭状态,即客户端已经没有要发送的数据了,但服务端若发送数据,则客户端仍要接收。
第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。
CLOSE-WAIT 状态问题:
客户端发送了 FIN 连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器会发送FIN 连接释放报文。
TIME-WAIT 状态问题
客户端接收到服务器端的 FIN 报文后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL(Maximum Segment Lifetime)。这么做有两个理由:
- 确保最后一个确认报文能够到达。如果 B 没收到 A 发送来的确认报文,那么就会重新发送连接释放请求报文,A 等待一段时间就是为了处理这种情况的发生。
- 等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一 个新的连接不会出现旧的连接请求报文。
通信双方建立TCP连接后,主动关闭连接的一方就会进入TIME_WAIT状态。
半关闭
当 TCP 链接中 A 向 B 发送 FIN 请求关闭,另一端 B 回应 ACK 之后(A 端进入 FIN_WAIT_2状态),并没有立即发送 FIN 给 A,A 方处于半连接状态(半开关),此时 A 可以接收 B 发送的数据,但是 A 已经不能再向 B 发送数据。
3. TCP为什么不能两次握手? 不是三次挥手?
不是两次握手:
为了实现可靠数据传输(有序,完整,无差错), TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤
为什么不是三次挥手的原因:
与握手的情况相似,即发送方A发出的第一个释放请求报文并没有丢失,而是在某些网络结点长时间滞留,以致延误到下次TCP连接的某个时间才到接收端B,本来这是一个早已失效的报文段,但接收到后误认为是发送方A请求释放连接,如果没有最后一次发送方发送确认报文,那么接收方就会在结束当前发送的报文后立即断开连接,那么就会影响当前的TCP连接
4. time_wait
①最后客户端的ACK为丢失,这时服务器会重传FIN,如果这时没有time_wait,A会处于一个closed状态,收到这个FIN会响应RST包,导致B端异常。
②等待2个MSL(最大分段寿命),以防止一些迟到的报文还没有在这个链接中消失。防止在下一次链接下会收到这一次的一些报文。
TCP keepalive, 以及和 HTTP keepalive 的区别
- HTTP Keep-Alive
http早期,每个http请求都要求打开一个tpc socket 连接,并且使用一次之后就断开这个tcp连接。使keep-alive可以改善这种状态,即在一次TCP连接中可以待续发送多份数据而不会断开连接。通过使用keep-alive机制,可以减少tcp连接建立次数,也意味着可以减少TIME_WAIT状态连接,以此提高性能和提高httpd服务器的吞吐率(更少的tcp连接意味着更少的系统内核调用, socket accept()和close()调用)。但是, keep-alive并不是免费的午餐,长时间的tcp连接容易导致系统资源无效占用。配置不当的keep- alive, 有时比重复利用连接带来的损失还更大。所以,正确地设置keep-alive timeout时间非常重要。
2.TCP KEEPALIVE
链接建立之后,如果应用程序或者上层协议一直不发送数据,或者隔很长时间才发送一次数据,当链接很久没有数据报文传输时如何去确定对方还在线,到底是掉线了还是确实没有数据传输,链接还需不需要保待,这种情况在TCP协议设计中是需要考虑到的。 TCP协议通过一种巧妙的方式去解决这个问题,当超过一段时间之后, TCP 自动发送一个数据为空的报文给对方,如果对方回应了这个报文,说明对方还在线,链接可以继续保持,如果对方没有报文返回,并且重试了多次之后则认为链接丢失,没有必要保持链接。
TCP keepalive机制和HTTP keep-alive机制是说的完全不同的两个东西, tcp keepalive是在ESTABLISH状态的时候,双方如何检测连接的可用行。而http keep alive说的是如何避免进行重复的TCP 三次握手和四次挥手的环节。
5. 什么是 TCP 粘包和拆包
TCP是个**“流”协议**,所谓流,就是没有界限的一串数据。大家可以想想河里的流水,是连成一片的,其间并没有分界线。 TCP底层并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的划分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP粘包和拆包问题。
假设客户端分别发送了两个数据包D1 D2给服务端,由于服务端一次读取到的字节数是不确定的,故可能存在以下种情况。
(1) 服务端分两次读取到了两个独立的数据包,分别是Dl D2, 没有粘包和拆包;
(2) 服务端一次接收到了两个数据包, Dl D2粘合在一起,被称为TCP粘包;
(3) 服务端分两次读取到了两个数据包, 第一次读取到了完整的D1 包和D2包的部分内容,第二次读取到了D2包的剩余内容,这被称为TCP拆包;
(4) 服务端分两次读取到了两个数据包,第一次读取到了D1包的部分内容Dl_L 第二次读取到了Dl包的剩余内容D1_2 D2包的整包;如果此时服务端TCP接收滑窗非常小,而数据包D1 D2 比较大,很有可能会发生第五种可能,即服务端分多次才能将Dl D2包接收完全,期间发生多次拆包。
解决方案:
- 客户端在发送数据包的时候,每个包都固定长度,比如1024个字节大小,如果客户端发送的数据长度不足1024个字节,则通过补充空格的方式补全到指定长度;
- 客户端在每个包的末尾使用固定的分隔符,例如\r\n,如果一个包被拆分了,则等待下一个包发送过来之后找到其中的\r\n,然后对其拆分后的头部部分与前一个包的剩余部分进行合并,这样就得到了一个完整的包;
- 将消息分为头部和消息体,在头部中保存有当前整个消息的长度,只有在读取到足够长度的消息之后才算是读到了一个完整的消息;
- 通过自定义协议进行粘包和拆包的处理。
6. tcp的拥塞控制和流量控制
发送窗口: 1.已被确认的 2.已发送,未确认 3.可用,还未发送的
接收窗口: 1.失序已缓存,但未被确认2.期待,但是还没有收到 3.可接受
- 流量控制:消除发送方使接收方缓存区溢出的可能**(关注网络边缘节点),使得发送方与接收方速率匹配。在通信过程之中,接收方根据自己接收缓存的大小,动态地调整发送方的发送窗口大小,用TCP报文段首部中的“接收窗口”字段值**,将未确认的数据量控制在接收窗口rwnd大小之内。有一个试探,TCP仅当它有数据或右确认要发时才会发送。所以发送端不知道接收端什么时候有位置,所以要发送一个只有一个字节的把报文,当B确认时,则缓存已清空。
- 拥塞控制:防止过多的数据注入网络,以使网络中的路由器或链路不会过载**(关注网络链路传输)。有一个门限值**,一开始拥塞窗口为1,进入慢启动,拥塞窗口呈指数增长,当到达门限值时,会进入拥塞避免,拥塞窗口呈线性增长。遇到三个冗余ACK,快速重传,门限值变为当时拥塞窗口的一半,拥塞窗口变成新的门限值+3,然后进入拥塞避免,呈线性增长。遇到超时,门限值变变为当时拥塞窗口的一半,之后将拥塞窗口置为1,将进入快速恢复。
7.TCP拥塞控制
1).慢启动:不要一开始就发送大量的数据,先探测一下网络的拥塞程度,也就是说由小到大逐渐增加拥塞窗口的大小;
2).拥塞避免:拥塞避免算法让拥塞窗口缓慢增长,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加1,而不是加倍,这样拥塞窗口按线性规律缓慢增长。
3).快重传:快重传要求接收方在收到一个 失序的报文段 后就立即发出 重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时捎带确认。快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。
4).快恢复:快重传配合使用的还有快恢复算法,当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把ssthresh门限减半,但是接下去并不执行慢开始算法:因为如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方现在认为网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将cwnd设置为ssthresh的大小,然后执行拥塞避免算法。
8. TCP如何保证可靠传输
- 校验和
- 序号和确认号
- 重传
- 三次握手四次挥手
- 流量控制
- 拥塞控制
9. 服务器怎么判断客户端断开了连接
检测连接是否丢失的方法大致有两种 keep_alive heart-beat
- (tcp 内部机制)采用TCP的keep_alive, 它会先要求此连接一定时间没有活动(一般是几个小时),然后发出数据段 经过多次尝试后(每次尝试之间也有时间间隔),如果仍没有响应,则判断连接中断。可想而知,整个周期需要很长的时间。
三个参数:tcp_keepalive_time/tcp_keepalive_probes/tcp_keepalive_intvl,分别表示连接闲置多久开始发keepalive的ack包、发几个ack包不回复才当对方死了、两个ack包之间间隔多长 - (应用层实现)采用心跳包,用于长连接的保活和断线处理。一个简单的heart-beat 实现一般测试连接是否中断采用的时间间隔都比较短,可以很快决定连接是否中断。并且,由于是在应用层实现,因为可以自行决定当判断连接中断后应该采取的行为,而keepalive在判断连接失败后只会将连接丢弃。
TCP如何保证可靠性
http://www.nowamagic.net/academy/detail/23350382
10.TCP中的四个计时器
包括重传计时器、坚持计时器、保活计时器、时间等待计时器
重传计时器(Retransmission Timer):
- 目的:为了控制丢失的报文段或者丢弃的报文段。这段时间为对报文段的等待确认时间。
- 创建时间:在TCP发送报文段时,会创建对次特定报文段的重传计时器。
- 可能发生的两种情况:在截止时间(通常为60秒)到之前,已经收到了对此特定报文段的确认,则撤销计时器;在截止时间到了,但为收到对此特定报文段的确认,则重传报文段,并且将计时器复位。
- 重传时间:2*RTT(Round Trip Time,为往返时间)
坚持计时器(Persistent Timer):
- 目的:主要解决零窗口大小通知可能导致的死锁问题
- 死锁问题的产生:当接收端的窗口大小为0时,接收端向发送端发送一个零窗口报文段,发送端即停止向对端发送数据。此后,如果接收端缓存区有空间则会重新给发送端发送一个窗口大小,即窗口更新。但接收端发送的这个确认报文段有可能会丢失,而此时接收端不知道已经丢失并认为自己已经发送成功,则一直处于等待数据的状态;而发送端由于没有收到该确认报文段,就会一直等待对方发来新的窗口大小,这样一来,双方都处在等待对方的状态,这样就形成了一种死锁问题。如果没有应对措施,这种局面是不会被打破的。为了解决这种问题,TCP为每一个连接设置了坚持计时器。
- 工作原理:当发送端TCP收到接收端发来的零窗口通知时,就会启动坚持计时器。当计时器的期限到达时,发送端就会主动发送一个特殊的报文段告诉对方确认已经丢失,必须重新发送。【这个特殊的报文段就称为探测报文段,探测报文段只有1个字节的大小,里边只有一个序号,该序号不需要被确认,甚至在计算其他部分数据的确认时该序号会被忽略。】
- 截止期的设置:设置为重传时间的值。但如果没有收到接收端的响应,则会发送另一个探测报文段,并将计时器的值加倍并复位,直到大于门限值(一般为60秒)。在此之后,发送端会每隔60秒发送一个探测报文段,直到窗口重新打开。
保活计时器(Keeplive Timer):
- 目的:主要是为了防止两个TCP连接出现长时间的空闲。当客户端与服务器端建立TCP连接后,很长时间内客户端都没有向服务器端发送数据,此时很有可能是客户端出现故障,而服务器端会一直处于等待状态。保活计时器就是解决这种问题而生的。
- 工作原理:每当服务器端收到客户端的数据时,都将保活计时器重新设置(通常设置为2小时)。过了2小时后,服务器端如果没有收到客户端的数据,会发送探测报文段给客户端,并且每隔75秒发送一个,当连续发送10次以后,仍没有收到对端的来信,则服务器端认为客户端出现故障,并会终止连接。
时间等待计时器(Time_Wait Timer):
- 时间等待计时器是在连接终止期间使用的。
- 当TCP关闭连接时并不是立即关闭的,在等待期间,连接还处于过渡状态。这样就可以使重复的FIN报文段在到达终点之后被丢弃。
- 时间设置:一般为报文段寿命期望值的2倍。
11. socket通信
close()和shuntdown()区别(知乎)
前置知识:FIN与close的行为
TCP下,本端和对端的交互情况如下:
-
某一端执行主动关闭操作(close)后,会让自己发送一个FIN报文给对端。
-
在接收到 FIN 报文后,对端发出 ACK 报文作为响应。之后在对端对 socket 的 read() 操作都会产生一个EOF,返回0。
close的效果则是引发一个FIN的发送,尝试关闭连接;同时关闭这个fd。 -
你向对端发送了一个FIN,表示你无话可说了
-
对端向你发送了ACK,表示对FIN的确认;
-
对端表示还有数据未发送,需要仍然向socket发送了数据
-
你的内核直接向对端发送了RST,重制了这个连接,你也没能收到这个数据
前置知识:shutdown的使用
shutdown(2) 是用来关闭某一个 sockfd 的。通过参数控制:
- SHUT_RD 拒绝对端发送
- SHUT_WR 拒绝本端发送
- SHUT_RDWR 拒绝本端发送和对端发送
在socket上调用 close() 会将双向通信通道的两端都关闭,而shutdown可以提供更细粒度的控制,比如只关一边。 值得注意的是,SHUT_RD 的实现不是标准的,因此编写可移植代码时,应当避免使用这个参数。
shutdown 在 标记 SHUT_WR 和 SHUT_RDWR 时,会发送一个FIN包给对端。表示自己没有东西要说了,同时会拒绝自己这边对已经shutdown的socket的写入
区别close & shutdown
close 会关闭fd,而shutdown不会;
- 在使用了shutdown SHUT_RDWR 后,仍然需要close来关闭这个文件描述符close 在fd被多进程持有或被复制时,不会立马关闭连接
- shutdown会直接关闭连接(发送FIN),而无论是否有其他打开的文件描述符指向套接字
三、网络层
1. 子网掩码
对外隐藏子网的存在
对内指示网络号和子网号的位置。
2. 路由器
路由表和转发表的区别
路由器的结构结构可划分为两大部分:路由选择部分和分组转发部分
路由选择部分也叫做控制部分,其核心构件是路由选择处理机。路由选择处理机的任务是根据所选定的路由协议构造出路由表,同时经常或定期地和相邻的路由器交换路由信息而不断地更新和维护路由表。
分组转发部分由三部分组成:交换结构、输入端口和输出端口。
交换结构的作用就是根据转发表(forwarding table)对分组进行处理,将某个输入端口进入的分组从一个合适的输入端口转发出去。
3. ICMP
从体系结构而言,位于IP层之上,ICMP保温封装在IP分组中
ICMP差错报文
ICMP询问报文
4. IPv6
IPv4数据报格式
IPv6数据包格式
IPv6与IPv4的区别
- 无检验和
- 中间结点不再负责分片和重组,由端节点负责
- 首部长度固定,加速中间结点转发速度
IPv4到IPv6的迁移
- 设立标志日,统一迁移
- 双栈技术
- 隧道技术
有了MAC地址,为什么还需要IP地址
MAC是主机全球唯一标识号,IP在网络传输中决定了下一跳(子网掩码)。
5. 路由协议小结
四、链路层
1. ARP(地址解析协议)
每个主机上有个IP到MAC地址的映射表,称ARP表,先看表里有没有IP,有直接查出mac地址,写入mac帧,发送到此mac地址。没有,就用广播帧广播 arp请求分组。同一个局域网里所有主机都收到,但是只有相应的ip做出相应。不在同一局域网,的到一个路由器的硬件地址,发给路由器,让他发给下一个网络。响应报文是单播。
2. 信道划分协议
TDMA
FDMA
3. VLAN
虚拟局域网(VLAN)是一组逻辑上的设备和用户,这些设备和用户并不受物理位置的限制,可以根据功能、部门及应用等因素将它们组织起来,相互之间的通信就好像它们在同一个网段中一样,由此得名虚拟局域网,由于交换机端口有两种VLAN属性,其一是VLANID,其二是VLANTAG,分别对应VLAN对数据包设置VLAN标签和允许通过的VLANTAG(标签)数据包,不同VLANID端口,可以通过相互允许VLANTAG,构建VLAN。
VLAN的优点如下:
- 提高网络性能。将广播包限制在VLAN内,从而有效控制网络的广播风暴,节省了网络带宽,从而提高网络处理能力。
- 增强网络安全。不同VLAN的设备不能互相访问,不同VLAN的主机不能直接通信,需要通过路由器或三层交换机等网络层设备对报文进行三层转发。
- 简化网络管理。同一个虚拟工作组的主机不会局限在某个物理范围内,简化了网络的管理,方便了不同区域的人建立工作组。