《面试必备知识》——计算机网络97问
问题目录(请善用CTRL+F):
1. TCP报文格式及首部含义?
-
头部长度:通常为20字节,有选项时更长
- 这里头部长度的1指代的是32位,即4个字节长度
- 因此4位的首部长度能够表示60字节
-
报文序号
- 标识报文中的第一个数据字节的序号
- 到达2^32-1后,重新回到0开始计数
- 初始连接请求报文中,SYN标志位也占1,因此第一字节序号为ISN+1
-
确认序号
- 接收方期望接收的下一个数据字节的序号
- ACK为1时有效
-
校验和
- 由首部和数据一起运算得到,用来校验报文数据是否丢失
-
紧急指针
- 紧急数据字节号(urgSeq)=TCP报文序号(seq)+紧急指针(urgpoint)−1
- 正偏移量
-
选项
- 常见的是MSS(最大报文大小),指明本端能够接收的最大长度的报文段
-
窗口大小
- 16位的窗口大小最多能放65536字节
- 如果想要使用更大的窗口,可以在选项中添加窗口的缩放比例因子来进行扩大,比例为0-14
2. IP报文格式及首部含义?
- 头部长度:通常20字节,有选项时更长,总共不超过60字节
- 校验和
- 仅对IP首部计算校验和
- TCP、UDP、ICMP等协议均在各自的首部中包含覆盖首部和数据的校验和
- 挂载协议标识
- 用来表示上层的传输层协议使用的是什么协议
- 分段偏移
- 当原始报文过大,以以太网帧为例,当大于1500字节的时候,会对原始报文进行分割,此时该字段就用来表示该分段在原始报文的位置
3. UDP报文格式及首部含义?
- 主要组成:源端口号、目标端口号、报文长度、检验和,一共8字节
- 报文长度
- 指首部和数据的总字节长度
3.1 UDP伪首部作用?
- 伪首部的出现:发送方或接收方根据IP报文首部获得8字节的源地址+目的地址、2字节的0字段+UDP协议字段、2字节的数据长度,得到12字节伪首部,临时添加在首部前面
- 伪首部的消失:发送方将计算完毕的校验和填入首部的校验和字段后,去除伪首部发送UDP报文
- 作用:仅仅是为了计算校验和
4. TCP三次握手的流程?
- 假设 A 为客户端,B 为服务器端。
- 首先 B 处于 LISTEN(监听)状态,等待客户的连接请求。
- A 向 B 发送连接请求报文,SYN=1,ACK=0,选择一个初始的序号 x。
- 在SYN建立连接的阶段会携带MSS选项字段来决定MSS报文的大小
- 默认是536字节,如果双方协商不成功
- B 收到连接请求报文,如果同意建立连接,则向 A 发送连接确认报文,SYN=1,ACK=1,确认号为 x+1,同时也选择一个初始的序号 y。
- 与此同时,B会将该连接放进半连接队列(SYN队列)
- A 收到 B 的连接确认报文后,还要向 B 发出确认,确认号为 y+1,序号为 x+1。
- 此时A已经可以携带数据
- B 收到 A 的确认后,连接建立。
- 此时,B的内核会将该连接从半连接队列中移除,然后创建新的完全连接,并添加到accept队列(全连接队列),等待应用程序调用accept函数取出来
5. 为什么需要三次握手?
- 防止历史连接请求初始化了连接
- 第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接。
- 客户端发送的连接请求如果在网络中滞留,那么就会隔很长一段时间才能收到服务器端发回的连接确认。客户端等待一个超时重传时间之后,就会重新请求连接。但是这个滞留的连接请求最后还是会到达服务器,如果不进行三次握手,那么服务器就会打开两个连接。如果有第三次握手,客户端会根据上下文(如确认号)判断服务端发来的确认连接是否是历史连接(此时客户端不处于SYN-SENT状态),如果是,客户端则发送RST报文,终止历史连接,避免错误打开连接。
- 同步双方初始序列号
- 在TCP协议中,报文的序列号和确认号是确保消息可靠送达的重要机制
- 因此,需要正确同步双方的初始序列号。而同步一方的初始序列号,需要一次请求报文和响应报文。因此,确认双方的初始序列号,需要进行三次握手
- 当客户端发送携带「初始序列号」的 SYN 报文的时候,需要服务端回一个 ACK 应答报文,表示客户端的 SYN 报文已被服务端成功接收,那当服务端发送「初始序列号」给客户端的时候,依然也要得到客户端的应答回应,这样一来一回,才能确保双方的初始序列号能被可靠的同步
- 避免资源浪费
- 与第一点相似,主要是为了避免重开连接导致浪费系统资源
6. 三次握手过程中未收到对方回复会怎么样?
- 服务端未收到第一次握手信息
- 服务端本身不会干什么,因为它还没有收到连接请求
- 客户端会不断地重试发送
- 客户端没有收到第二次握手信息
- 服务端的响应由于网络原因一直没有抵达客户端,此时服务端会不断重试
- 服务端没有收到第三次握手信息
- 服务端没有收到客户端的确认信息,这时候服务端会重传报文,如果重传次数达到上限时仍然没有收到确认报文,那么accept会返回-1,此时服务端这边的连接建立失败
- 此时客户端已经进入连接状态,可以发送消息了,但是服务端的连接失败了(accept返回-1),此时客户端再向服务端发送数据,服务端在收到后会发送RST报文给客户端
7. 如何绕过三次握手?
- 在普通的三次握手的流程中,头两次握手的期间是不能携带数据的
- 也就是必须等到一个RTT时间后才能发送数据
- 使用TCP Fast Open,可以减少TCP建立连接发送数据的延迟
在客户端首次建立连接时的过程:
- 客户端发送 SYN 报文,该报文包含 Fast Open 选项,且该选项的 Cookie 为空,这表明客户端请求 Fast Open Cookie;
- 支持 TCP Fast Open 的服务器生成 Cookie,并将其置于 SYN-ACK 数据包中的 Fast Open 选项以发回客户端;
- 客户端收到 SYN-ACK 后,本地缓存 Fast Open 选项中的 Cookie。
所以,第一次发起 HTTP GET 请求的时候,还是需要正常的三次握手流程。
之后,如果客户端再次向服务器建立连接时的过程:
- 客户端发送 SYN 报文,该报文包含「数据」(对于非 TFO 的普通 TCP 握手过程,SYN 报文中不包含「数据」)以及此前记录的 Cookie;
- 支持 TCP Fast Open 的服务器会对收到 Cookie 进行校验:如果 Cookie 有效,服务器将在 SYN-ACK 报文中对 SYN 和「数据」进行确认,服务器随后将「数据」递送至相应的应用程序;如果 Cookie 无效,服务器将丢弃 SYN 报文中包含的「数据」,且其随后发出的 SYN-ACK 报文将只确认 SYN 的对应序列号;
- 如果服务器接受了 SYN 报文中的「数据」,服务器可在握手完成之前发送「数据」,这就减少了握手带来的 1 个 RTT 的时间消耗;
- 客户端将发送 ACK 确认服务器发回的 SYN 以及「数据」,但如果客户端在初始的 SYN 报文中发送的「数据」没有被确认,则客户端将重新发送「数据」;
- 此后的 TCP 连接的数据传输过程和非 TFO 的正常情况一致。
所以,之后发起 HTTP GET 请求的时候,可以绕过三次握手,这就减少了握手带来的 1 个 RTT 的时间消耗。
8. 初始序列号 ISN 是如何随机产生的?
起始 ISN 是基于时钟的,每 4 毫秒 + 1,转一圈要 4.55 个小时。
RFC1948 中提出了一个较好的初始化序列号 ISN 随机生成算法。
ISN = M + F (localhost, localport, remotehost, remoteport)
- M 是一个计时器,这个计时器每隔 4 毫秒加 1。
- F 是一个 Hash 算法,根据源 IP、目的 IP、源端口、目的端口生成一个随机数值。要保证 Hash 算法不能被外部轻易推算得出,用 MD5 算法是一个比较好的选择
9. 既然 IP 层会分片,为什么 TCP 层还需要 MSS 呢?
- MTU 和 MSS
-
MTU:一个网络包的最大长度,以太网中一般为 1500 字节;
-
MSS:除去 IP 和 TCP 头部之后,一个网络包所能容纳的 TCP 数据的最大长度;
-
假设TCP的报文均由IP层进行分片;
-
当TCP的报文长度大于MTU时,报文会进行分片,然后发送给目标主机,再由目标主机进行组装,上传到传输层
-
然而,如果有一个IP分片丢失了,那么整个IP报文需要重传
-
因为IP层本身无超时重传机制,超时重传机制是靠传输层的TCP来保证的;
-
当接收方发现TCP报文中的一片丢失后,不会响应对应报文的ACK给对方,发送方在超时后就会重发TCP报文
-
到达IP层后则需再次分片发送,效率低下
-
针对上述情况,为了达到最佳的传输性能,TCP 协议在建立连接的时候通常要协商双方的 MSS 值,当 TCP 层发现数据超过 MSS 时,则就先会进行分片,当然由它形成的 IP 包的长度也就不会大于 MTU ,自然也就不用 IP 分片了
- 经过 TCP 层分片后,如果一个 TCP 分片丢失后,进行重发时也是以 MSS 为单位,而不用重传所有的分片,大大增加了重传的效率。
10. SYN攻击是什么?
- TCP 连接建立是需要三次握手,假设攻击者短时间伪造不同 IP 地址的 SYN 报文,服务端每接收到一个 SYN 报文,就进入SYN_RCVD 状态,但服务端发送出去的 ACK + SYN 报文,无法得到未知 IP 主机的 ACK 应答,久而久之就会占满服务端的 SYN 接收队列(未连接队列),使得服务器不能为正常用户服务
- 一旦服务端接收到SYN后,会为该连接分配一个TCB(Transmission Control Block),通常一个TCB至少需要280个字节,在某些操作系统中TCB甚至需要1300个字节
- 半连接队列的个数一般是有限的,在SYN攻击下,服务器会打开大量的半连接,分配TCB,从而耗尽服务器的资源,使得正常的连接请求无法得到响应
10.1 SYN攻击的分类有哪些?
- Direct Attack 直接攻击
- 攻击方使用固定的源地址发起攻击
- 这种比较容易预防,只要将特定的IP列入黑名单即可
- Spoofing Attack 攻击方使用变化的源地址发起攻击
- Distributed Direct Attack 这种攻击主要是使用僵尸网络进行固定源地址的攻击
10.2 SYN攻击的解决方法有什么?
-
主要针对后两种攻击
-
修改Linux 内核参数,控制队列大小和当队列满时应做什么处理
- 当网卡接收数据包的速度大于内核处理的速度时,会有一个队列保存这些数据包。控制该队列的最大值如下参数:net.core.netdev_max_backlog
- SYN_RCVD 状态连接的最大个数:net.ipv4.tcp_max_syn_backlog
- 超出处理能时,对新的 SYN 直接回 RST,丢弃连接:net.ipv4.tcp_abort_on_overflow
-
开启 tcp_syncookies 功能
-
sysctl -w net.ipv4.tcp_syncookies=1
-
本质上属于延缓TCB分配方法
-
收到SYN攻击,会导致SYN队列被占满,对于后续来到的SYN请求,不再放在队列中,而是直接回应一个带SYN cookie的SYN-ACK包给客户端
-
服务器根据当前状态计算出一个值,放在己方发出的 SYN+ACK 报文中发出,当客户端返回 ACK 报文时,取出该值验证,如果合法,就认为连接建立成功,然后放到accept队列
-
后续应用程序调用accept()从accept队列中取出连接
-
-
增大半连接队列
-
增大半连接队列,我们得知不能只单纯增大 tcp_max_syn_backlog 的值,还需一同增大 somaxconn 和 backlog,也就是增大全连接队列
-
sysctl -w net.ipv4.tcp_max_syn_backlog=2048
-
-
减少 SYN+ACK 重传次数
-
减少 SYN+ACK 的重传次数,以加快处于 SYN_REVC 状态的 TCP 连接断开
-
sysctl -w net.ipv4.tcp_synack_retries=3 sysctl -w net.ipv4.tcp_syn_retries=3
-
-
全连接队列和半连接队列一起构成未决连接队列,这个队列的大小为backlog,是listen的参数
10.3 SYN cookie是什么?
- 服务器端根据本次连接的信息、时间生成一个SYN cookie做为报文初始序号
- 当客户端收到后,会向服务端发送响应报文
- 服务端根据响应报文的确认号-1就可以得到之前的SYN cookie
- 对SYN cookie按照规则进行解析就可以判断响应是否超时,以及连接信息是否有伪装等,避免浪费服务器的资源
11. TCP控制位有哪些?分别有什么用?
- SYN(synchronous建立联机)
- 用于建立连接,该报文的序列号用于初始序号的确定
- ACK(acknowledgement 确认)
- 表示当前报文的应答字段有效
- 除了最初的SYN报文外,其它报文必须将该位设置为1
- PSH(push传送)
- 接收方应该尽快将报文提交给应用层
- 为0则可以先进行缓存
- FIN(finish结束)
- 表示今后不会再有数据发送,希望断开连接
- 通信结束后,双方交换fin报文结束通信
- RST(reset重置)
- TCP连接出现异常,必须强制断开连接
- 常见情况:连接请求到达时,目标端口没有进程在监听
- URG(urgent紧急)
- 表示包中有需要紧急处理的数据,结合紧急指针一起使用
- Sequence number(顺序号码)
- 对字节流进行标号,表示第一个字节的编号
- Acknowledge number(确认号码)
- 期望收到的下一个报文的序号
12. TCP首部格式以及字段含义?
- 序号:
- 用于对字节流进行编号。例如序号为 301,表示第一个字节的编号为 301,如果携带的数据长度为 100字节,那么下一个报文段的序号应为 401。
- 确认号 :
- 期望收到的下一个报文段的序号。例如 B 正确收到 A 发送来的一个报文段,序号为 501,携带的数据长度为 200 字节,因此 B 期望下一个报文段的序号为 701,B 发送给 A 的确认报文段中确认号就为 701。
- 数据偏移 :
- 指的是数据部分距离报文段起始处的偏移量,实际上指的是首部的长度。
- 确认 ACK :
- 当 ACK=1 时确认号字段有效,否则无效。TCP 规定,在连接建立后所有传送的报文段都必须把ACK 置 1
- 同步 SYN :
- 在连接建立时用来同步序号。当 SYN=1,ACK=0 时表示这是一个连接请求报文段。若对方同意建立连接,则响应报文中 SYN=1,ACK=1。
- 终止 FIN :
- 用来释放一个连接,当 FIN=1 时,表示此报文段的发送方的数据已发送完毕,并要求释放连接。
- 窗口 :
- 窗口值作为接收方让发送方设置其发送窗口的依据。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。
13. 四次挥手的流程?
以下描述不讨论序号和确认号,因为序号和确认号的规则比较简单。并且不讨论 ACK,因为 ACK 在连接建立之后都为 1。
- A 发送连接释放报文,FIN=1。
- B 收到之后发出确认,此时 TCP 属于半关闭状态,B 能向 A 发送数据但是 A 不能向 B 发送数据。
- 当 B 不再需要连接时,发送连接释放报文,FIN=1。
- A 收到后发出确认,进入 TIME-WAIT 状态,等待 2 MSL(最大报文存活时间)(Linux 系统里 2MSL 默认是 60 秒)后释放连接。
- B 收到 A 的确认后释放连接。
14. 为什么需要4次挥手?
客户端发送了 FIN 连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器会发送 FIN 连接释放报文。 TIME_WAIT 客户端接收到服务器端的 FIN 报文后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL。这么做有两个理由:
- 确保最后一个确认报文能够到达。如果 B 没收到 A 发送来的确认报文,那么就会重新发送连接释放请求报文,A 等待一段时间就是为了处理这种情况的发生。
- 至少允许报文丢失一次
- 等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。
15. 四次挥手可以变为三次吗?
- 一种情况时延迟确认,将第二步的ack与第三步的fin包一起发送给对端
- 另外一种是服务端已经没有什么数据要发送了,就可以将fin和ack合并一个包发送给对端
16. FIN-WAIT2等待时间是多少?
- 主动关闭的一端调用完close以后(即发FIN给被动关闭的一端, 并且收到其对FIN的确认ACK)则进入FIN_WAIT_2状态。如果这个时候因为网络突然断掉、被动关闭的一段宕机等原因,导致主动关闭的一端不能收到被动关闭的一端发来的FIN(防止对端不发送关闭连接的FIN包给本端),这个时候就需要FIN_WAIT_2定时器, 如果在该定时器超时的时候,还是没收到被动关闭一端发来的FIN,那么直接释放这个链接,进入CLOSE状态
17. 针对 TCP 应该如何 Socket 编程?
-
流程:
-
服务端和客户端初始化 socket,得到文件描述符;
-
服务端调用 bind,将监听socket绑定在 IP 地址和端口;
-
服务端调用 listen,进行监听;
-
服务端调用 accept,等待客户端连接;
-
客户端调用 connect,向服务器端的地址和端口发起连接请求;
-
服务端 accept 返回用于传输的 socket 的文件描述符;
-
客户端调用 write 写入数据;服务端调用 read 读取数据;
-
客户端断开连接时,会调用 close,那么服务端 read 读取数据的时候,就会读取到了 EOF,待处理完数据后,服务端调用 close,表示连接关闭。
-
注意点:
- 服务端调用 accept 时,连接成功了会返回一个已完成连接的 socket,后续用来传输数据
- 所以,监听的 socket 和真正用来传送数据的 socket,是「两个」 socket,一个叫作监听 socket,一个叫作已完成连接 socket
-
服务器:
-
创建socket -> int socket(int domain, int type, int protocol);
-
domain:协议域,决定了socket的地址类型,IPv4为AF_INET。
-
type:指定socket类型,SOCK_STREAM为TCP连接。
-
protocol:指定协议。IPPROTO_TCP表示TCP协议,为0时自动选择type默认协议。
-
-
绑定socket和端口号 -> int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
-
sockfd:socket返回的套接字描述符,类似于文件描述符fd。
-
addr:有个sockaddr类型数据的指针,指向的是被绑定结构变量。
// IPv4的sockaddr地址结构 struct sockaddr_in { sa_family_t sin_family; // 协议类型,AF_INET in_port_t sin_port; // 端口号 struct in_addr sin_addr; // IP地址 }; struct in_addr { uint32_t s_addr; }
- addrlen:地址长度。
-
-
监听端口号 -> int listen(int sockfd, int backlog);
-
sockfd:要监听的sock描述字。
-
backlog:socket可以排队的最大连接数。
-
-
接收用户请求 -> int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
-
sockfd:服务器socket描述字。
-
addr:指向地址结构指针。
-
addrlen:协议地址长度。
-
注:一旦accept某个客户机请求成功将返回一个全新的描述符用于标识具体客户的TCP连接。
-
-
从socket中读取字符 -> ssize_t read(int fd, void *buf, size_t count);
-
fd:连接描述字。
-
buf:缓冲区buf。
-
count:缓冲区长度。
-
注:大于0表示读取的字节数,返回0表示文件读取结束,小于0表示发生错误。
-
-
关闭socket -> int close(int fd);
-
fd:accept返回的连接描述字,每个连接有一个,生命周期为连接周期。
-
注:sockfd是监听描述字,一个服务器只有一个,用于监听是否有连接;fd是连接描述字,用于每个连接的操作。
-
-
-
客户机:
-
创建socket -> int socket(int domain, int type, int protocol);
-
连接指定计算机 -> int connect(int sockfd, struct sockaddr* addr, socklen_t addrlen);
-
sockfd客户端的sock描述字。
-
addr:服务器的地址。
-
addrlen:socket地址长度。
-
-
向socket写入信息 -> ssize_t write(int fd, const void *buf, size_t count);
-
fd、buf、count:同read中意义。
-
大于0表示写了部分或全部数据,小于0表示出错。
-
-
关闭oscket -> int close(int fd);
- fd:同服务器端fd。
-
18. HTTP协议和HTTPS协议的默认端口号?
-
http:80
-
https:443
19. http协议的流程?
- 首先进行域名解析。
- 浏览器发起HTTP请求。
- 接下来到了传输层,选择传输协议。TCP或者UDP,TCP是可靠的传输控制协议,对HTTP请求进行封装,加入了端口号等信息。
- 然后到了网络层,通过IP协议将IP地址封装为IP数据报;然后此时会用到ARP协议,主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址,找到目的MAC地址;
- 接下来到了数据链路层,把网络层交下来的IP数据报添加首部和尾部,封装为MAC帧,现在根据目的mac开始建立TCP连接,三次握手,接收端在收到物理层上交的比特流后,根据首尾的标记,识别帧的开始和结束,将中间的数据部分上交给网络层,然后层层向上传递到应用层;
- 服务器响应请求并返回客户端要的资源,传回给客户端;
- 断开TCP连接,浏览器对页面进行渲染呈现给客户端。
20. cookies和session的含义与区别?
- Cookie :
- Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器之后向同一服务器再次发起请求时被携带上,用于告知服务端两个请求是否来自同一浏览器。由于之后每次请求都会需要携带 Cookie 数据,因此会带来额外的性能开销(尤其是在移动环境下)。
- 用途:
- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
- Session :
- Session 是存储在 web 服务器端的一块信息。 session 对象存储特定用户会话所需的属性及配置信息。当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。
- 不同:
- **存取方式的不同:**Cookie 只能存储 ASCII 码字符串,而 Session 则可以存储任何类型的数据,因此在考虑数据复杂性时首选Session;
- **隐私策略的不同:**Cookie 存储在浏览器中,容易被恶意查看。如果非要将一些隐私数据存在 Cookie 中,可以将 Cookie 值进行加密,然后在服务器进行解密。而Session存储在服务器上,不存在敏感信息泄露的风险。
- **服务器压力的不同:**对于大型网站,如果用户所有的信息都存储在 Session 中,那么开销是非常大的,因此不建议将所有的用户信息都存储到 Session 中。 而Cookie保管在客户端,不占用服务器资源。假如并发阅读的用户十分多,Cookie是很好的选择。关于Google、Baidu、Sina来说,Cookie或许是唯一的选择。
- **浏览器支持的不同:**无论客户端做怎样的设置, session 都能够正常工作。当客户端禁用 cookie 时将无法使用 cookie。 假如客户端浏览器不支持Cookie,需要运用Session以及URL地址重写。需要注意的是一切的用到Session程序的URL都要进行URL地址重写,否则Session会话跟踪还会失效。关于WAP应用来说,Session+URL地址重写或许是它唯一的选择
- **跨域支持上的不同:**Cookie支持跨域名访问,例如将domain属性设置为“.biaodianfu.com”,则以“.biaodianfu.com”为后缀的一切域名均能够访问该Cookie。跨域名Cookie如今被普遍用在网络中,例如Google、Baidu、Sina等。而Session则不会支持跨域名访问。Session仅在他所在的域名内有效。
- 参考:
21. Http协议如何保证安全性?
- 重要的数据,要加密:
- 比如用户名密码,我们需要加密,这样即使被抓包监听,他们也不知道原始数据是什么。
- 非重要数据,要签名:
22. 阻塞式io和非阻塞式io有什么区别?
- 读:
- 在阻塞条件下,如果没有发现数据在网络缓冲中会一直等待,当发现有数据的时候会把数据读到用户指定的缓冲区。但是如果这个时候读到的数据量比较少,比参数中指定的长度要小,read并不会一直等待下去,而是立刻返回。read的原则是数据在不超过指定的长度的时候有多少读多少,没有数据就会一直等待。所以一般情况下我们读取数据都需要采用循环读的方式读取数据,一次read完毕不能保证读到我们需要长度的数据,read完一次需要判断读到的数据长度再决定是否还需要再次读取。
- **在非阻塞的情况下,**read的行为是如果发现没有数据就直接返回,如果发现有数据那么也是采用有多少读多少的进行处理.对于读而言,阻塞和非阻塞的区别在于没有数据到达的时候是否立刻返回。
- 写:
- **在阻塞的情况,**是会一直等待直到write完全部的数据再返回。
- 非阻塞写的情况,是采用可以写多少就写多少的策略。与读不一样的地方在于,有多少读多少是由网络发送端是否有数据传输到本地内核缓存为准。但是对于可以写多少是由本地的网络堵塞情况为标准的,在网络阻塞严重的时候,网络层没有足够的内存来进行写操作,这时候就会出现写不成功的情况,阻塞情况下会尽可能(有可能被中断)等待到数据全部发送完毕,对于非阻塞的情况就是一次写多少算多少,没有中断的情况下也还是会出现write到一部分的情况。
23. 网络协议有哪7层?
- 应用层
- 用户接口、应用程序;
- Application典型设备:网关;
- 典型协议、标准和应用:TELNET、FTP、HTTP
- 表示层
- 数据表示、压缩和加密presentation
- 典型设备:网关
- 典型协议、标准和应用:ASCLL、PICT、TIFF、JPEG|MPEG
- 表示层相当于一个东西的表示,表示的一些协议,比如图片、声音和视频MPEG。
- 会话层
- 会话的建立和结束;
- 典型设备:网关;
- 典型协议、标准和应用:RPC、SQL、NFS、X WINDOWS、ASP
- 传输层
- 主要功能:端到端控制Transport;
- 典型设备:网关;
- 典型协议、标准和应用:TCP、UDP、SPX
- 网络层
- 主要功能:路由、寻址Network;
- 典型设备:路由器;
- 典型协议、标准和应用:IP、IPX、APPLETALK、ICMP;
- 数据链路层
- 主要功能:保证无差错的疏忽链路的data link;
- 典型设备:交换机、网桥、网卡;
- 典型协议、标准和应用:802.2、802.3ATM、HDLC、FRAME RELAY;
- 物理层
- 主要功能:传输比特流Physical;
- 典型设备:集线器、中继器
- 典型协议、标准和应用:V.35、EIA/TIA-232.
24. TCP和UDP的区别?
- TCP:
- 可靠,稳定 TCP的可靠体现在TCP在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制,在数据传完后,还会断开连接用来节约系统资源。
- 慢,效率低,占用系统资源高,易被攻击。TCP在传递数据之前,要先建连接,这会消耗时间,而且在数据传递时,确认机制、重传机制、拥塞控制机制等都会消耗大量的时间,而且要在每台设备上维护所有的传输连接,事实上,每个连接都会占用系统的CPU、内存等硬件资源。 而且,因为TCP有确认机制、三次握手机制,这些也导致TCP容易被人利用,实现DOS、DDOS、CC等攻击。
- UDP:
- 快,比TCP稍安全 UDP没有TCP的握手、确认、窗口、重传、拥塞控制等机制,UDP是一个无状态的传输协议,所以它在传递数据时非常快。没有TCP的这些机制,UDP较TCP被攻击者利用的漏洞就要少一些。但UDP也是无法避免攻击的,比如:UDP Flood攻击……
- 不可靠,不稳定 因为UDP没有TCP那些可靠的机制,在数据传递时,如果网络质量不好,就会很容易丢包。
- 使用场景:
- 整个数据要准确无误的传递给对方,这往往用于一些要求可靠的应用,比如HTTP、HTTPS、FTP等传输文件的协议,POP、SMTP等邮件传输的协议。 在日常生活中,常见使用TCP协议的应用如下: 浏览器,用的HTTP FlashFXP,用的FTP Outlook,用的POP、SMTP Putty,用的Telnet、SSH QQ文件传输 …………
- 当对网络通讯质量要求不高的时候,要求网络通讯速度能尽量的快,这时就可以使用UDP。 比如,日常生活中,常见使用UDP协议的应用如下: QQ语音 QQ视频 TFTP ……
- 区别小结:
- TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
- TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
- TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
- UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
- 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
- TCP首部开销20字节;UDP的首部开销小,只有8个字节(UDP的速度快,开销少)
- TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
- 参考:TCP和UDP的最完整的区别
25. HTTP的常用方法
- GET:
- 获取资源
- 当前网络请求中,绝大部分使用的是 GET 方法。
- HEAD :
- 获取报文首部
- 和 GET 方法类似,但是不返回报文实体主体部分。
- 主要用于确认 URL 的有效性以及资源更新的日期时间等。
- POST :
- 传输实体主体
- POST 主要用来传输数据,而 GET 主要用来获取资源。
- PUT :
- 上传文件
- 由于自身不带验证机制,任何人都可以上传文件,因此存在安全性问题,一般不使用该方法。
- PATCH :
- 对资源进行部分修改
- PUT 也可以用于修改资源,但是只能完全替代原始资源,PATCH 允许部分修改。
- DELETE :
- 删除文件
- 与 PUT 功能相反,并且同样不带验证机制。
- OPTIONS :
- 查询支持的方法
- 查询指定的 URL 能够支持的方法。
- 会返回 Allow: GET, POST, HEAD, OPTIONS 这样的内容。
- CONNECT :
- 要求在与代理服务器通信时建立隧道
- ***L(Secure Sockets Layer,安全套接层)和 TLS(Transport Layer Security,传输层安全)协议把通信内容加密后经网络隧道传输。
- TRACE :
- 追踪路径
- 服务器会将通信路径返回给客户端。
- 发送请求时,在 Max-Forwards 首部字段中填入数值,每经过一个服务器就会减 1,当数值为 0 时就停止传输。
- 通常不会使用 TRACE,并且它容易受到 XST 攻击(Cross-Site Tracing,跨站追踪)。
26. Http get和post的区别?
- 根据http规范,get用于信息获取,应该是安全的和幂等的
- 安全意味着该操作用于获取信息而非修改信息。换句话说,GET 请求一般不应产生副作用。
- 幂等的意味着对同一URL的多个请求应该返回同样的结果。
- 根据http规范,POST表示可能修改变服务器上的资源的请求,即post用于提交数据。
- get提交参数追加在url后面,post参数可以通过http body提交。
- get的url会有长度上的限制,则post的数据则可以非常大,post的数据量受限于处理程序的处理能力。
- get提交信息明文显示在url上,不够安全,post提交的信息不会在url上显示
- get提交可以被浏览器缓存,post不会被浏览器缓存。
- 登录页面有可能被浏览器缓存
- 其他人可以看到浏览器的历史记录
- get参数只能使用ascii码,post参数可以使用标准字符集
27. URL和URI的区别?
- URI包括URL和URN两个类别,URL是URI的子集,所以URL一定是URI,而URI不一定是URL
- URI:
- Universal Resource Identifier 统一资源标志符
- 用来标识抽象或物理资源的一个紧凑字符串。
- URL :
- Universal Resource Locator 统一资源定位符.
- 一种定位资源的主要访问机制的字符串,一个标准的URL必须包括:protocol、host、port、path、parameter、anchor。
- URN :
- Universal Resource Name 统一资源名称.
- 通过特定命名空间中的唯一名称或ID来标识资源。
28. 从浏览器中输入url之后发生了什么?
-
DNS查询
- 先在本地域名服务器中根据域名查询IP
- 向根域名服务器发送请求,查找IP
- 向顶级域名服务器发送请求,查找IP
-
TCP连接
-
发送HTTP请求
-
Server处理HTTP请求并返回HTTP报文
-
浏览器解析并渲染页面
-
连接断开
-
域名解析 --> 发起TCP的3次握手 --> 建立TCP连接后发起http请求 --> 服务器响应http请求,浏览器得到html代码 --> 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等) --> 浏览器对页面进行渲染呈现给用户。
29. 域名解析每次都去访问根域名服务器的话,根域名服务器压力不会很大吗?DNS优化方法?
- 浏览器缓存
- 系统缓存
- 路由器缓存
- IPS服务器缓存
- 根域名服务器缓存
- 顶级域名服务器缓存
- 主域名服务器缓存
30. OSI七层协议模型、TCP/IP四层模型和五层协议体系结构之间的关系?
31. osi为什么有了七层还有五层的概念?
- 七层协议的理论虽然完整,但是不太实用而且很复杂
- 四层结构是实现模型,而5层结构则是结合两种模型得出的,目的是为了更好描述网络接口层
32. TCP可靠性机制有哪些?
32.1 TCP如何保证消息顺序?
- TCP协议会给每个数据包分配一个序列号
- 发送方在发送消息后,会等待接收方对该报文进行确认,如果一段时间内没有收到确认,那么会触发超时重传,发送方会重传该报文
- 接收方接收到数据后,会先进行缓存,如果数据的顺序是正确的,那么就上传到应用层使用,否则暂时保存在缓冲区
32.2 TCP的重传机制是怎么实现的?
32.2.1 超时重传机制?
-
在发送数据时,设定一个定时器,当超过指定的时间后,没有收到对方的 ACK 确认应答报文,就会重发该数据
-
数据包丢失或者确认应答丢失就会触发
-
数据包在网络中的往返时间(RTT)
- 超时重传时间(RTO)
- 很显然,RTO应该设置为略大于RTT,以便获得最高的性能
- 但是由于网络情况不断变化,RTT时间是一个动态变化的值
- Linux系统下是采用某种公式来计算对应的RTO时间(公式的参数是通过大量的实验得到的)
- 如果超时重发的数据,再次超时的时候,又需要重传的时候,TCP 的策略是超时间隔加倍
- 也就是每当遇到一次超时重传的时候,都会将下一次超时时间间隔设为先前值的两倍。两次超时,就说明网络环境差,不宜频繁反复发送。
32.2.2 快速重传机制?
- 发送方收到了三次同样的 ACK 确认报文,于是就会触发快速重发机制
- 但是在重传的时候无法确认是重传之前一个,还是所有
32.2.3 SACK 选项的作用?
-
在 TCP 头部「选项」字段里加一个 SACK 的东西
-
将缓存的地图发送给发送方
- 告诉发送方我收到了哪些数据
-
只重传丢失的数据
-
Linux 通过net.ipv4.tcp_sack 参数打开这个功能(Linux 2.4 后默认打开)
-
注意:启动sack后,接受方接收到带sack的报文也认为收到重复ack
- 开启该功能需要双方支持并协商成功
- D-SACK
- 使用了 SACK 来告诉「发送方」有哪些数据被重复接收了
- 使用D-SACK的好处
- 可以让「发送方」知道,是发出去的包丢了,还是接收方回应的 ACK 包丢了;
- 可以知道是不是「发送方」的数据包被网络延迟了;
- 可以知道网络中是不是把「发送方」的数据包给复制了;
- 在 Linux 下可以通过 net.ipv4.tcp_dsack 参数开启/关闭这个功能(Linux 2.4 后默认打开)。
32.3 滑动窗口的作用是什么?
- 没有滑动窗口的话
- 仅按数据包进行确认应答,数据包的往返时间越长,通信的效率就越低
- 使用滑窗
- 窗口大小就是指无需等待确认应答,而可以继续发送数据的最大值
- 窗口内的数据可以不用等待接收方的应答,先行发送出去
- 如果收到了应答,就可以将数据从窗口内清除
- 利用ACK700就能确认前面的数据发送无误,这就是累计确认或者累计应答
32.3.1 窗口大小由哪一方决定?
- TCP 头里有一个字段叫 Window,也就是窗口大小。
- 这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。
- 所以,一般是否接收方决定。
- 发送方发送的数据大小不能超过接收方的窗口大小,否则接收方就无法正常接收到数据。
32.3.2 程序是如何表示发送方的四个部分的呢?
- 一个指针指向已发送且收到了确认的第一个字节的序列号,绝对指针
- 一个指针指向已发送但未收到了确认的第一个字节的序列号,绝对指针
- 一个指针指向未发送,且超出窗口的第一个字节序列号,相对指针,由第一个指针和窗口大小得到
32.3.3 窗口关闭问题如何解决?
- 如果窗口大小为 0 时,就会阻止发送方给接收方传递数据,直到窗口变为非 0 为止,这就是窗口关闭。
- 死锁问题见下图
- 解决方法:
- TCP 为每个连接设有一个持续定时器,只要 TCP 连接一方收到对方的零窗口通知,就启动持续计时器
- 如果持续计时器超时,就会发送窗口探测 ( Window probe ) 报文,而对方在确认这个探测报文时,给出自己现在的接收窗口大小
32.3.4 糊涂窗口综合症如何解决?
-
接收方太忙,导致发送方的发送窗口越来越小
-
到最后,如果接收方腾出几个字节并告诉发送方现在有几个字节的窗口,而发送方会义无反顾地发送这几个字节,这就是糊涂窗口综合症
-
TCP + IP 头有 40 个字节,如果只传输几个字节的数据,代价很大
-
问题形成原因:
- 接收方可以通告一个小的窗口
- 而发送方可以发送小数据
-
解决方法:
- 接收方判断窗口大小小于小于 MSS 与 1/2 缓存大小中的最小值时,向发送方通告窗口为 0
- 发送方使用 Nagle 算法
- 要等到窗口大小 >= MSS 或是 数据大小 >= MSS
- 收到之前发送数据的 ack 回包
-
Nagle 算法:
- 一个 TCP 连接上最多只能有一个未被确认的未完成的小分组,在它到达目的地前,不能发送其它分组。
- 在上一个小分组未到达目的地前,即还未收到它的 ack 前,TCP 会收集后来的小分组。当上一个小分组的 ack 收到后,TCP 就将收集的小分组合并成一个大分组发送出去。
32.4 流量控制目的?
- 发送方不能无脑的发数据给接收方,要考虑接收方处理能力
- 本质上利用的还是滑动窗口的原理
- 不会发送超过约定的滑动窗口大小的数据
- TCP 通过让接收方指明希望从发送方接收的数据大小(窗口大小)来进行流量控制
32.5 TCP拥塞机制介绍一下?
-
流量控制只能控制通信双方的流量,但是计算机网络是一个共享的环境,有可能会因为其它主机的通信而使得网络拥塞
-
目的
- 防止过多的数据注入到网络中,避免网络中路由器、链路过载
32.5.1 什么是拥塞窗口?和发送窗口有什么关系呢?
- 拥塞窗口 cwnd是发送方维护的一个 的状态变量,它会根据网络的拥塞程度动态变化的
- 发送窗口的值是swnd = min(cwnd, rwnd),也就是拥塞窗口和接收窗口中的最小值
32.5.2 那么怎么知道当前网络是否出现了拥塞呢?
- 发生了超时重传,就会认为网络出现了拥塞
32.5.3 拥塞控制算法介绍一下
32.5.3.1 慢启动
-
一开始一点一点提高发送数据包的数量
-
cwnd = 10
-
当发送方每收到一个 ACK,就拥塞窗口 cwnd 的大小就会加 1
-
呈指数增长
-
慢启动门限 ssthresh:
- 默认:65536
- 当 cwnd < ssthresh 时,使用慢启动算法。
- 当 cwnd >= ssthresh 时,就会使用「拥塞避免算法」。
-
拥塞窗口的1代表的是可以发送一个MSS大小的数据
32.5.3.2 拥塞避免算法
- 每当收到一个 ACK 时,cwnd 增加 1/cwnd
- 将指数级增长变为了线性增长
- 增长速度变慢,但是最终还是会进入网络拥塞
- 此时会采用拥塞发生算法
32.5.3.3 拥塞发生算法(快速重传算法)
- 超时重传
- ssthresh 设为 cwnd/2,
- cwnd 重置为 1
- 因为超时没有收到任何ack,所以认为网络拥塞严重
- 快速重传
- ssthresh = cwnd/2;
- cwnd = cwnd/2 ,也就是设置为原来的一半;
- 进入快速恢复算法
- 因为还是能连续收到接收方的3个ack,说明拥塞不算太严重
32.5.3.4 快速恢复算法
- 拥塞窗口 cwnd = ssthresh + 3 ( 3 的意思是确认有 3 个数据包被收到了)
- 重传丢失的数据包
- 如果再收到重复的 ACK,那么 cwnd 增加 1
- 如果收到新数据的 ACK 后,设置 cwnd 为 ssthresh,接着就进入了拥塞避免算法
33. 关闭TCP连接的方法?
- RST 报文关闭
- 进程异常退出,发送RST报文,不走四挥流程,暴力关闭连接
- FIN 报文关闭
34. 调用 close 函数 和 shutdown 函数有什么区别?
-
close 函数意味着完全断开连接
- 既不能发送,也不能接收
- 调用了 close 函数的一方的连接叫做「孤儿连接」
-
把全双工的两个方向的连接都关闭了
-
shutdown函数可以通过参数控制只关闭一个方向上的连接
- SHUT_RD(0):关闭连接的「读」这个方向,如果接收缓冲区有已接收的数据,则将会被丢弃,并且后续再收到新的数据,会对数据进行 ACK,然后悄悄地丢弃。也就是说,对端还是会接收到 ACK,在这种情况下根本不知道数据已经被丢弃了。
- SHUT_WR(1):关闭连接的「写」这个方向,这就是常被称为「半关闭」的连接。如果发送缓冲区还有未发送的数据,将被立即发送出去,并发送一个 FIN 报文给对端。
- SHUT_RDWR(2):相当于 SHUT_RD 和 SHUT_WR 操作各一次,关闭套接字的读和写两个方向。
35. TCP全连接队列和半连接队列的作用?
- 服务端并发处理大量请求时,如果 TCP 全连接队列过小,就容易溢出。发生 TCP 全连接队溢出的时候,后续的请求就会被丢弃,这样就会出现服务端请求数量上不去的现象
35.1 全连接队列满了,就只会丢弃连接吗?
tcp_abort_on_overflow 共有两个值分别是 0 和 1,其分别表示:
- 0 :如果 accept 队列满了,那么 server 扔掉 client 发过来的 ack ;
- 1 :如果 accept 队列满了,server 发送一个 RST 包给 client,表示废掉这个握手过程和这个连接;
35.2 如何增大 TCP 全连接队列呢?
- TCP 全连接队列足最大值取决于 somaxconn 和 backlog 之间的最小值,也就是 min(somaxconn, backlog)
- somaxconn 是 Linux 内核的参数,默认值是 128,可以通过 /proc/sys/net/core/somaxconn 来设置其值;
- backlog 是 listen(int sockfd, int backlog) 函数中的 backlog 大小,Nginx 默认值是 511,可以通过修改配置文件设置其长度;
- NGINX设置
- 服务端执行 ss 命令,查看 TCP 全连接队列使用情况:
- 从上面的执行结果,可以发现全连接队列使用增长的很快,但是一直都没有超过最大值,所以就不会溢出,那么 netstat -s 就不会有 TCP 全连接队列溢出个数的显示:
- 溢出示例
36 如何查看 TCP 的连接状态?
TCP 的连接状态查看,在 Linux 可以通过 netstat -napt 命令查看。
37 假设客户端有多个网卡,就会有多个 IP 地址,那 IP 头部的源地址应该选择哪个 IP 呢?
- 此时会根据路由表来进行匹配,确定哪一个网卡作为源地址IP
- 主要是根据网络号进行匹配
- 如果没有匹配,则选用最后一个,表示默认网关
- 即后续就把包发给路由器,Gateway 即是路由器的 IP 地址。
38 交换机如何转发包信息?
- 交换机的各个端口是没有MAC地址的,是二层网络设备,工作在MAC层
- 交换机的 MAC 地址表主要包含两个信息:
- 一个是设备的 MAC 地址,
- 另一个是该设备连接在交换机的哪个端口上。
-
根据接收到的包上面的接收方的MAC地址进行匹配,可以得到应该转发到的端口信息。
-
只要有对交换机发送过消息,MAC地址就会记录下来
-
如果没有找到MAC地址,就将包转发到除了源端口之外的所有端口上
39 路由器是怎么工作的?
- 基于IP设计,三层网络设备,各个端口都有MAC地址和IP地址
- 收到包后,通过包的MAC头部判断是否给自己的,是的话就放入缓冲区,否则丢弃
- 然后去掉MAC头部,根据IP头部的目的IP地址在路由表中进行匹配
- 找到对应的接口信息,然后将报文转发到该接口
- 是在没有找到就会使用最后的默认路由
-
通过路由表进行匹配后有两种结果:
- 如果网关是一个 IP 地址,则这个IP 地址就是我们要转发到的目标地址,还未抵达终点,还需继续需要路由器转发。
- 如果网关为空,则 IP 头部中的接收方 IP 地址就是要转发到的目标地址,也是就终于找到 IP 包头里的目标地址了,说明已抵达终点。
-
根据路由表得到的接口就是MAC的发送地址
-
然后查询ARP缓存或者使用ARP广播得到目标地址的MAC地址
-
两者组合得到MAC头部,然后继续进行传输
-
在网络包传输的过程中,源 IP 和目标 IP 始终是不会变的,一直变化的是 MAC 地址,因为需要 MAC 地址在以太网内进行两个设备之间的包传输
40. HTTP 是什么?描述一下
-
HTTP 是超文本传输协议,也就是HyperText Transfer Protocol。
-
HTTP 是一个在计算机世界里专门在「两点」之间「传输」文字、图片、音频、视频等「超文本」数据的「约定和规范」。
-
HTTP 是超文本传输协议,是在两台计算机之间传送文字、图片、视频等超文本数据的约定和规范
41. 简述 HTTP1.0/1.1/2.0 的区别?
https://mp.weixin.qq.com/s/amOya0M00LwpL5kCS96Y6w
41.1 HTTP1.0
- 默认使用短连接,每次请求都需要建立连接
41.2 HTTP1.1
-
使用 TCP 长连接的方式改善了 HTTP/1.0 短连接造成的性能开销。
-
支持 管道(pipeline)网络传输,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。
-
开始支持获取文件的部分内容,这支持了并行下载和断点续传。通过在Header的两个参数实现
-
高延迟——队头阻塞
- 顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一并被阻塞,会导致客户端迟迟收不到数据
-
无状态特性 — 阻碍交互
- 无状态是指协议对于连接状态没有记忆能力
-
明文传输 — 不安全性
- 传输内容没有加密,中途可能被篡改和劫持
-
不支持服务端推送
41.3 HTTP2.0
-
头部压缩
- HTTP/2 会压缩头(Header)如果你同时发出多个请求,他们的头是一样的或是相似的,那么,协议会帮你消除重复。
- 使用的是HPACK算法。在客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了
- 每次请求和响应只发送差异头部
- 原理
- 维护一份相同的静态字典(Static Table),包含常见的头部名称,以及特别常见的头部名称与值的组合;
- 维护一份相同的动态字典(Dynamic Table),可以动态的添加内容;
- 支持基于静态哈夫曼码表的哈夫曼编码(Huffman Coding);
- 静态字典作用:
- 对于完全匹配的头部键值对,例如 “:method :GET”,可以直接使用一个字符表示;
- 对于头部名称可以匹配的键值对,例如 “cookie :xxxxxxx”,可以将名称使用一个字符表示。
- 同时,浏览器和服务端都可以向动态字典中添加键值对,之后这个键值对就可以使用一个字符表示了。需要注意的是,动态字典上下文有关,需要为每个 HTTP/2 连接维护不同的字典。在传输过程中使用,使用字符代替键值对大大减少传输的数据量。
-
二进制格式
- 报文采用二进制格式。头信息和数据体都是二进制,统称为帧:头信息帧和数据帧
- 当计算机收到报文后,无需将明文报文转成二进制,而是直接解析二进制报文,增加了数据传输的效率
-
数据流
- 数据包不按顺序发送
- 每个请求或者回应的所有数据包称为一个数据流
- 每个数据流会标记一个独一无二的编号,其中客户端为奇数,服务器为偶数。
- 使得并行的数据传输成为可能
- 通过标记来指出它属于哪个回应
- 通过给数据包添加标签来区分不同的请求和响应
-
多路复用
- 在一个连接中能够并发多个请求或回应,不用按顺序一一对应
- 最终根据每个请求和响应上的标记组合成正常的请求和响应
- 即对于A、B请求,A的请求在先,但是A的请求处理很慢,B的请求在后,但是处理速度较快。在这种情况下,可以先回应A已完成的部分,然后回应B请求,待A完成后,再回应剩余部分
- 避免了1.1管道传输过程中,由于前面一个请求的响应被阻塞了,导致后面请求的响应也被阻塞了
- 好处
- 单连接多资源的方式,减少服务端的链接压力,内存占用更少,连接吞吐量更大;由于减少TCP 慢启动时间,提高传输的速度
- 在一个连接中能够并发多个请求或回应,不用按顺序一一对应
-
服务器推送
- 服务器不再完全是被动响应
- 譬如说在浏览器请求HTML的时候,可以提前将可能用到的静态文件主动发送给客户端,减少延时等待
-
不足:
- HTTP/1.1 中的管道( pipeline)传输中如果有一个请求阻塞了,那么队列后请求也统统被阻塞住了
- HTTP/2 多请求复用一个TCP连接,一旦发生丢包,就会阻塞住所有的 HTTP 请求。
-
不足:
- TCP 以及 TCP+TLS 建立连接的延时
- TCP连接需要3次握手,即1.5个RTT时间
- TLS大致需要1-2个RTT
- TCP 的队头阻塞并没有彻底解决
- 丢包发生时,需要进行重传确认,此时会阻塞整个TCP连接中的所有请求
- 多路复用导致服务器压力上升
- 多路复用没有限制同时请求数
- 请求的平均数量与往常相同,但实际会有许多请求的短暂爆发,导致瞬时 QPS 暴增
- 多路复用容易 Timeout
- 大批量的请求同时发送,由于 HTTP2 连接内存在多个并行的流,而网络带宽和服务器资源有限,每个流的资源会被稀释,虽然它们开始时间相差更短,但却都可能超时
- TCP 以及 TCP+TLS 建立连接的延时
41.4 HTTP3.0
- 将HTTP下层的TCP改成了UDP
- 基于UDP的QUIC协议可以实现类似TCP的可靠传输
- QUIC 有自己的一套机制可以保证传输的可靠性的。当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响
- QUIC 是一个在 UDP 之上的伪 TCP + TLS + HTTP/2 的多路复用的协议
- TL3 升级成了最新的 1.3 版本,头部压缩算法也升级成了 QPack
- HTTPS 要建立一个连接,要花费 6 次交互,先是建立三次握手,然后是 TLS/1.3 的三次握手。QUIC 直接把以往的 TCP 和 TLS/1.3 的 6 次交互合并成了 3 次,减少了交互次数
42. 同步异步、阻塞非阻塞的区别?
- 阻塞/非阻塞:
- 描述的是调用者调用方法后的状态
- 阻塞:调用者在调用方法后需要一直等待结果,不能干别的事情
- 非阻塞:调用者在调用后无需等待,可以干别的事情
- 同步/异步:
- 描述的是方法跟调用者间通信的方式
- 同步:调用的方法需要自身完成,在调用方法后,调用者需要一直等待结果返回,也就是要不停地查询结果是否得出
- 异步:调用的方法无需自身完成,调用方在调用方法后直接返回,调用方法通过回调或者消息通知等方式来通知调用者结果
43. ARP协议可以确定MAC地址,为什么还需要IP协议?
- 使用IP协议更像是一种分层的思想
- ARP协议使用的是广播的方式来确定目标的MAC地址
- 但是在世界范围内不可能通过广播的方式来从数以千万的计算机中找到目标MAC地址而不超时
- 因此通过IP协议将报文送达至指定的网段中,然后再使用ARP协议找到目标的MAC地址
44. 连接异常与RST的区别?
- TCP连接出现严重的错误,必须释放连接就会将报文的RST置位
- 这种方式属于异常终止连接:
- 丢弃任何尚未发送的数据,立即发送 RST 报文段
- RST 接收方会区分另一端是异常关闭还是正常关闭,从而做出不同响应
- 任何收到 RST 段的一方根本不会为这个 RST 进行确认
- 主动发送 RST 段的一方,不会进入 TIME_WAIT 状态
45. 半打开(Half-Open)是什么意思?
- 如果一方已经关闭或异常终止,而另一方却对此毫不知情,这种连接就称为半打开的。
- 处于半打开的 A 向主机 B 发送数据:
- 如果主机 B 仍然断网或者已经连接上网络,但是服务未启动,A 向 B 发送数据,经过数次超时重传后放弃连接,并发送 RST 段给对方(不一定非得发送,这系统实现有关)。
- 如果主机 B 已经连接上网络且重新启动了服务,A 向 B 发送数据,B 收到后因为不认识这个连接,向 A 发送 RST 段。
46. 累计确认和捎带确认是什么意思?
47. PSH标志位的作用?
- 用来通知TCP什么时候将数据发送出去(从发送缓冲区中取数据),以及 read 函数什么时候将数据从接收缓冲区读取都是未知的
- 发送方由TCP模块自行决定什么时候将缓冲区数据打包成TCP报文,并加上PSH标志。一般来说,write一次就会发送一次,或者缓冲区满了也会立即发送
- 接收方收到了包含PSH标志的TCP报文后,立即将缓冲区的所有数据推送给应用程序
- 总结
- 通知发送方立即发送报文
- 通知接收方立即将数据推送到应用程序
48. UDP相关问题
48.1 概述
- 无连接协议。意味着各个报文没有顺序性,你可能先发了一个数据包 A,后发一个数据包 B,结果对方却先收到 B,后收到 A
- UDP 协议不提供可靠性,这意味着不能保证对端一定能收到数据
48.2 UDP也可以是有连接的
-
有连接的协议,存在sockname + peername
- bind 函数本质上就是 setsockname,而 connect 函数本质上就是 setpeername 函数
-
无连接的情况,总是缺少peername
-
如果想让UDP套接字称为有连接,只需要指定它的peername即可
-
即在UDP客户端调用connect函数
-
有连接的UDP套接字的变化
-
- 不能再使用 sendto 函数指定目的 IP 和 port,这个参数需要指定成 NULL,或者干脆使用 write 函数。
-
- 不需要再使用 recvfrom 来获取数据报的发送者了,应该改用 read 或 recv 等函数。
-
- 有连接的 UDP 套接字引发错误,会返回给它所在的进程。无连接的 UDP 套接字不会。
-
48.3 有连接和无连接的性能比较
- 无连接在每次发送数据时,需要在内核中暂时创建该套接字,发送完数据后再次断开
- 有连接会在第一次的时候建立连接,然后一直复用
- 因此有连接的性能会更好一些
48.4 UDP如何增加可靠性?(使用UDP做为传输层协议时,如何确保数据传输的可靠性?)
- 借鉴TCP的思想,可以采用确认+重传的方式来增加UDP的可靠性
- 与TCP的不同:
- 可靠性的安全机制可以根据自己的需求进行灵活的设计
- 可以利用RUDP 等开源库来实现可靠的UDP传输
49. TCP粘包问题的原因和解决方法是什么?
-
主要原因:
- TCP 协议是面向字节流的协议,它可能会组合或者拆分应用层协议的数据;
- 应用层协议的没有定义消息的边界导致数据的接收方无法拼接数据;
-
发送方原因:
-
Nagle算法:
- 当数据包较小时,不会将数据包直接发送出去,而是在缓存区间等待一段时间,看一下后续有没有其它的数据包可以合并一起发送
- 能够降低网络拥塞的可能性,减少数据发送的额外开销(IP首部+TCP首部将近40字节)
- 内核参数:
- TCP_NODELAY
- TCP_CORK
- 延迟发送数据
- 当发送的数据小于 MSS 时,TCP 协议就会延迟 200ms 发送该数据或者等待缓冲区中的数据超过 MSS
-
接收方原因:
- TCP接收到数据包时,并不会马上交到应用层进行处理,或者说应用层并不会立即处理
- TCP将接收到的数据包保存在接收缓存里,然后应用程序主动从缓存读取收到的分组
- 当接收速度大于应用程序的读取速度,应用程序就有可能得到首尾相连粘在一起的包
-
消息边界
- 由于TCP协议是面向字节流的协议,它有可能组合或者拆分应用层协议的数据,因此,应用层的协议需要自己划分消息边界。
- 使用固定长度的消息
- 在协议头中增加表示负载长度的字段
- 举例:
- HTTP 消息中,使用Content-Length 头表示 HTTP 消息的负载大小,这样接收方在接收到足够的字节数后,就可以分离出完整的HTTP消息
- HTTP还会使用基于终结符的策略
- 终结符不能包含在数据正文中
- 在使用块传输机制时,不再包含Content-Length字段,使用负载为0的HTTP消息作为终结符表示消息的边界
-
UDP协议是面向报文的
-
UDP的发送单元与应用程序的消息单元是一一对应的关系,因此不存在将包的数据组合或者拆分的问题,本身就具备了消息边界,也就不存在粘包问题
-
单个报文不能超过MTU大小,否则IP层会拆分
-
对于TCP而言,多个数据包可以一次接收完成,然后放在缓冲区中
-
但是对于UDP而言,不论缓冲区有多大,每个数据包需要单独一次接收动作,然后将接收的数据包挂载在接收端的链式结构上,每一次接收端读取数据时会从链上读取一个数据包出来。而且UDP本身支持一对多的通信,因此数据包会保留消息头(消息来源地址、端口等消息),对于接收端而言能够更好地区分不同的数据包,避免粘包问题
50. 点对点和端对端的区别
-
点对点
- ==发送端把数据传给与它直接相连的设备==,这台设备在合适的时候又把数据传给与之直接相连的下一台设备,通过一台一台直接相连的设备,把数据传到接收端
- 优点:发送端发送完数据后,任务就结束了,不会浪费发送端资源
- 如果接收设备故障,就利用存储转发技术进行缓冲
- 不足:发送数据后,不知道接收端是否成功接收和何时接收
-
端对端
- 数据传输前,经过各种各样的交换设备,在两端设备间建立一条链路,就象它们是直接相连的一样,链路建立后,发送端就可以发送数据,直至数据发送完毕,接收端确认接收成功
- 发送前,经过各种交换设备建立一条链路后,发送端再发送数据,而且发送端需要一直等待,直到接收端确认成功
- 优点:确认消息送达,中间设备无需存储转发,延迟低
- 不足:发送端需要一直参与整个过程,浪费发送端资源
- 如果接收设备故障,那么端到端不可能实现
-
数据可靠性
-
数据链路层和网络层一般是点对点
-
传输层一般是端对端
51. 在浏览器输入 URL 回车之后发生了什么?
过程 | 使用的协议 |
---|---|
1、浏览器查找域名DNS的IP地址 DNS查找过程(浏览器缓存、路由器缓存、DNS缓存) | DNS:获取域名对应的ip |
2、根据ip建立TCP连接 | TCP:与服务器建立连接 |
3、浏览器向服务器发送HTTP请求 | HTTP:发送请求 |
4、服务器响应HTTP响应 | HTTP |
5、浏览器进行渲染 |
-
URL 解析
- 判断输入的是否为一个合法的URL
-
DNS查询(域名解析)
- 首先检查本地是否有缓存
- 浏览器缓存
- 操作系统缓存,本地hosts文件
- 路由器缓存
- IPS DNS 服务器缓存
- 发送网络请求来查询
- 本地域名服务器先找根域名服务器
- 再找顶级域名服务器
- 最后找权威域名服务器
- 首先检查本地是否有缓存
-
得到IP地址后,进行TCP连接
- 三次握手
-
连接成功后,发送http请求
-
服务器处理请求
-
浏览器接收响应
- 对接收到的响应资源分析
- 根据不同的响应码做不同的事情
- 根据响应类型来解析响应内容
-
渲染页面
- 不同内核的渲染过程有所不同
52. 套接字类型有哪些?
- 数据报套接字(Datagram sockets):
- 无连接的服务
- 主要用于UDP协议
- 流套接字(Stream sockets)
- 面向连接
- 主要用于TCP协议
- 原始套接字(Raw sockets)
- 可以直接接收和发送IP数据包,无需基于特定的传输层协议
53. UDP协议的特点?
-
无连接协议,无需建立连接就可以发送数据
-
特点:
- 速度快
- 无需建立连接,因此没有建立连接的时延
- 无连接状态
- TCP需要维护序号、确认号、拥塞控制参数、发送缓存等数据
- UDP没有这些数据,也不存在发送缓存和接收缓存,因此使用UDP协议一般能支持更多的活跃用户
- 报文首部开销小
- 8个字节
- TCP为20字节
- UDP协议本身是不保证报文的可靠送达,但是应用层可以自己采取措施(如增加确认和重传机制),从而保证数据的可靠传输
-
组成:
- 源端口号
- 目标端口号
- 长度
- 校验和
- 前面四个都是16位,一共8字节的头部
- 数据
-
UDP的不可靠原因在于它虽然提供了差错检测(通过校验和),但是对于差错没有恢复功能,更没有重传机制
-
UDP收到应用层数据会立即交给IP层进行发送
54. UDP与TCP区别?
-
TCP提供面向连接的传输,UDP提供无连接的传输
-
TCP提供可靠的传输,UDP不保证可靠传输
-
TCP面向字节流,有额外的分组开销;UDP面向数据报,没有分组开销
-
TCP有拥塞和流控机制;UDP在网络繁忙的情况依然会继续发送
-
上层协议
-
UDP
- DNS
-
TCP
- HTTP,FTP
55. DNS何时使用TCP协议,何时使用UDP协议?
- DNS作为应用层协议,占用端口53,同时使用UDP和TCP
- 当DNS进行区域传输的时候会使用TCP协议,其它时候会使用UDP协议
- DNS规范中有两种类型的DNS服务器:主DNS服务器和辅助DNS服务器
- 在一个区中,主DNS服务器从自己本机的数据文件中读取该区的DNS数据信息,而辅助DNS服务器则从区的主DNS服务器中读取该区的DNS数据信息。
- 当一个辅助DNS服务器启动时,它需要与主DNS服务器通信,并加载数据信息,这就叫做区传送(zone transfer)
- 辅助DNS服务器会定时向主DNS服务器同步数据,如果数据变动,则进行区域传送,此时使用TCP,因为传送的数据量较多
- UDP是面向报文的,一般UDP长度不会大于512字节。TCP允许报文长度超过512字节,TCP协议能够对报文进行拆分和重组
- 而且使用TCP保证了数据同步的准确性
- 客户端在进行域名解析的时候会使用UDP协议
- 查询域名的返回结果一般不大于512字节
- 使用UDP能够减轻DNS服务器的负担,提高响应速度
- 很多DNS服务器仅支持UDP查询包
56. 为什么UDP报文大小要小于512字节?
- 在局域网通信的时候,数据帧长度需要在46-1500字节之间,去出到IP头部和UDP报文首部,大概剩下1472字节
- 但是在进行Internet编程的时候,由于Internet上不同路由器的MTU值可能有所不同,如果我们假定MTU为1500来发送数据的,而途经的某个网络的MTU值小于1500字节,那么系统将会使用一系列的机制来调整MTU值,使数据报能够顺利到达目的地,这样就会做许多不必要的操作.
- 鉴于Internet上的标准MTU值为576字节,所以我建议在进行Internet的UDP编程时.最好将UDP的数据长度控件在548字节(576-8-20)以内.
- 因此为了适应网络环境,一般UDP报文的长度不会大于512字节
当然,这个没有唯一答案,相对于不同的系统,不同的要求,其得到的答案是不一样的。
我这里仅对像ICQ一类的发送聊天消息的情况作分析,对于其他情况,你或许也能得到一点帮助:首先,我们知道,TCP/IP通常被认为是一个四层协议系统,包括链路层,网络层,运输层,应用层.UDP属于运输层,
下面我们由下至上一步一步来看:以太网(Ethernet)数据帧的长度必须在46-1500字节之间,这是由以太网的物理特性决定的.这个1500字节被称为链路层的MTU(最大传输单元).但这并不是指链路层的长度被限制在1500字节,其实这这个MTU指的是链路层的数据区.并不包括链路层的首部和尾部的18个字节.
所以,事实上,这个1500字节就是网络层IP数据报的长度限制。因为IP数据报的首部为20字节,所以IP数据报的数据区长度最大为1480字节.而这个1480字节就是用来放TCP传来的TCP报文段或UDP传来的UDP数据报的.又因为UDP数据报的首部8字节,所以UDP数据报的数据区最大长度为1472字节.这个1472字节就是我们可以使用的字节数。
当我们发送的UDP数据大于1472的时候会怎样呢? 这也就是说IP数据报大于1500字节,大于MTU.这个时候发送方IP层就需要分片(fragmentation). 把数据报分成若干片,使每一片都小于MTU.而接收方IP层则需要进行数据报的重组. 这样就会多做许多事情,而更严重的是,由于UDP的特性,当某一片数据传送中丢失时,接收方便 无法重组数据报.将导致丢弃整个UDP数据报。
因此,在普通的局域网环境下,我建议将UDP的数据控制在1472字节以下为好.
进行Internet编程时则不同,因为Internet上的路由器可能会将MTU设为不同的值. 如果我们假定MTU为1500来发送数据的,而途经的某个网络的MTU值小于1500字节,那么系统将会使用一系列的机 制来调整MTU值,使数据报能够顺利到达目的地,这样就会做许多不必要的操作.
鉴于Internet上的标准MTU值为576字节,所以我建议在进行Internet的UDP编程时. 最好将UDP的数据长度控件在548字节(576-8-20)以内
57. 域名分类
- 根域名用"."表示?
58. 根域名服务器的个数?
- IPV4:13
- IPV6:25
59. DNS缓存是怎么实现的?
- 进行域名解析的时候,会查看浏览器缓存、系统缓存、hosts文件,都没有才去LDNS查询
- 对于一个域名123.abc.qq.com.cn
- LDNS也会先看一下有没有123.abc.qq.com.cn的缓存,有就直接返回,没有,就继续看一下abc.qq.com.cn,qq.com.cn,com.cn,.cn的权威域名服务器的地址
- 如果有,则直接去对应的服务器那里进行解析
- 没有才去问根服务器
60. ICMP协议介绍一下?
-
ICMP协议,全称Internet Control Message Protocol,也叫互联网控制报文协议
-
常用类型:
- 查询报文
- 用来主动查询网络数据包是否可以到达目标主机
- 差错报文
- 用来通报源主机,发送数据包出错,到不了指定的网络、主机或者端口
- 查询报文
-
查询报文:
- 典型应用为ping程序,一种主动请求,并且获得主动应答的ICMP协议
- 主动请求的报文,称为ICMP请求数据包(ICMP echo request),主动请求的回复,ICMP响应数据包(ICMP echo reply)
-
差错报文
- 当互联网协议在传输过程中发生错误,会给源主机发送ICMP差错报文
- 分类:
- 终点不可达
- 源站抑制
- 源主机发送速度过快,目标主机处理不过来,告诉源主机放慢速度
- 超时
- IP数据报有TTL存活时间,每经过一个路由节点减一,到零还没有送到目标主机,就会发送超时的差错报文
- 路由重定向
- 通知下次发送给另外一个路由
-
典型应用:
-
PING,见下面
-
Traceroute
-
W10下命令:tracert www.baidu.com
-
使用的是ICMP差错报文的原理,可以用来跟踪网络数据包的路由途径
-
traceroute to blog.chenishr.com (120.77.213.253), 30 hops max, 60 byte packets 1 172.17.0.1 (172.17.0.1) 1.168 ms 1.091 ms 1.033 ms 2 192.168.5.1 (192.168.5.1) 15.025 ms 15.352 ms 15.948 ms 3 192.168.0.2 (192.168.0.2) 14.760 ms 14.683 ms 14.621 ms 4 * * * 5 113.106.40.50 (113.106.40.50) 208.131 ms 202.105.155.205 (202.105.155.205) 208.044 ms 61.146.241.233 (61.146.241.233) 208.000 ms 6 183.56.65.6 (183.56.65.6) 208.619 ms 183.56.65.14 (183.56.65.14) 91.293 ms 183.56.65.86 (183.56.65.86) 91.100 ms 7 119.147.223.110 (119.147.223.110) 90.981 ms 92.300 ms * 8 183.2.182.130 (183.2.182.130) 92.160 ms 58.61.162.134 (58.61.162.134) 92.146 ms 92.076 ms 9 183.61.45.10 (183.61.45.10) 92.041 ms 183.2.184.134 (183.2.184.134) 91.943 ms 183.61.45.10 (183.61.45.10) 91.948 ms 10 116.251.113.142 (116.251.113.142) 91.867 ms * 42.120.242.218 (42.120.242.218) 91.772 ms 11 42.120.253.2 (42.120.253.2) 91.730 ms 42.120.253.6 (42.120.253.6) 91.687 ms 116.251.117.153 (116.251.117.153) 103.880 ms 12 * * * 13 * * * 14 120.77.213.253 (120.77.213.253) 103.499 ms 103.443 ms 103.401 ms
-
序号表示经过的第几个路由,后接的IP地址即为该路由的IP
-
Traceroute默认向每个网关发送三个探测数据包,那三个值是网关响应后返回的时间。星号表示网关没有返回数据
-
底层原理:
- 利用了IP数据报的TTL字段和ICMP的差错类型报文
- 首先TTL设置为1,得到第一个路由返回的ICMP超时差错报文,以此类推,一直到到达目标主机为止
- Traceroute 给目标主机发送一份UDP数据,但是端口号为不可能的值(大于30000),目标主机的任何程序都不会使用该端口。这样,目标主机会给程序返回端口不可达的差错报文,程序就会知道数据包已经到达目标主机,不再发送探测报文
- 通过以上信息,就可以将网络数据包的路由途径绘制出来
-
61. PING协议介绍一下?
-
ICMP协议
-
互联网报文控制协议,工作在网络层
-
作用
- 确认IP包是否成功送达目标地址,报告发送过程中IP包被废弃的原因、改善网络设置等
- 检测目标地址是否可达
-
PING过程
- 源主机构建一个ICMP请求数据包,里面包含了类型字段(8,代表请求数据包),顺序号(用于区分连续ping时发出去的多个数据包,每发一个,增加1),发送时间(用于计算RTT)
- 然后该数据包再加上目标IP地、本机MAC地址和目标MAC地址等信息后,会发送出去
- 目标主机收到数据包后,会构建一个ICMP响应数据包,类型字段为0,序号为接收到的请求报文的序号,然后发送给源主机
- 在规定时间内,如果源主机没有收到ICMP的应答包,说明目标主机不可达,否则,说明主机可达
- 在收到响应后,源主机用当前时刻减去发送时刻,就能得到数据包的延迟时间
62. 长连接和短连接介绍一下?
-
短连接
- 客户端与服务端每进行一次HTTP请求,都会建立一次连接
- 应用场合
- 并发量大,但是每个用户不需要频繁操作的情况
- 用户登录场景
-
长连接
- 报文首部:Connection:keep-alive
- 当客户端和服务端建立连接后,在后续的请求中会复用这个连接,直到某一方主动断开连接
- 服务端会通过探测报文的方法来检测连接中的另外一方是否已经断开
-
如何选择
-
长连接适合操作频繁,点对点通讯,且连接数不会太多的情况
- 数据库连接
-
由于长连接会占用服务端的连接资源,短连接用完就会断开,因此对于大并发,大量连接的场景比较适用
- WEB网站的http服务一般用短连接
63. 并行连接是什么?
-
针对短连接的优化方案
-
允许客户端打开多条连接,并行执行多个事务,每个事务都有自己的TCP连接
-
有效利用带宽资源(但是由于带宽有限,因此带宽不足的情况下,性能提升很小)
-
利用浏览器多线程的能力,能够进行并发下载
-
长连接相比于并行连接的优势
- 避免了每个事务都会打开/关闭一条新的连接,造成时间和带宽的耗费
- 避免了 TCP 慢启动特性的存在导致的每条新连接的性能降低
- 可打开的并行连接数量实际上是有限的,持久连接则可以减少建立的连接的数量
64. 说一下ssl/tls过程?(Https通信过程)
-
客户端发出一个 client hello 消息,携带的信息包括
- 所支持的SSL/TLS 版本列表;支持的加密算法;所支持的数据压缩方法;随机数A
-
服务端响应一个 server hello 消息,携带的信息包括
- 协商采用的SSL/TLS 版本号;会话ID;随机数B;服务端数字证书 serverCA
- 双向认证的情况下,服务端需要对客户端进行认证,会同时发送一个client certificate request,表示请求客户端的证书
-
客户端校验服务端的数字证书;校验通过之后发送随机数C,该随机数称为pre-master-key,使用数字证书中的公钥加密后发出
- 由于服务端请求客户端的证书,因此,客户端会使用私钥加密一个随机数随着客户端的证书一起发出
-
服务端校验客户端的证书,然后将客户端加密的随机数C解密
- 根据随机数A,B,C产生对称秘钥,加密一个finish消息发送至客户端
-
客户端根据同样的随机数和算法生成对称秘钥,加密一个finish消息发送至服务端
-
双方解密成功后,握手成功,之后的数据均通过对称秘钥加密传输
-
https://www.nowcoder.com/discuss/613239?source_id=profile_create_nctrack&channel=-1
Client Hello 客户端发起HTTPS请求
Server Hello 服务端向客户端发送 Server Hello 消息,这个消息会从 Client Hello 传过来的 Support Ciphers 里确定一份加密套件,这个套件决定了后续加密和生成摘要时具体使用哪些算法,另外还会生成一份随机数 Random2。
- 注意,至此客户端和服务端都拥有了两个随机数(Random1+ Random2),这两个随机数会在后续生成对称秘钥时用到。
Certificate 服务端返回公钥和CA证书(数字证书)到客户端
- 该证书通常有两个目的:1. 身份验证;2. 证书中包含服务器的公钥,该公钥结合密码套件的密钥协商算法协商出预备主密钥
Server Key Exchange 该消息是有条件才发,例如,如果是DH算法,这里发送服务器使用的DH参数。RSA算法不需要这一步。它发送的条件是,如果证书包含的信息不足以进行密钥交换,那么必须发送该信息。
Server Hello Done ,服务器发送完上述信息之后,会立刻发送该信息,然后等到客户端的响应。该信息的主要作用有:
Certificate Verify,客户端解析证书,客户端接收后会验证证书的安全性,验证通过后取出证书中的服务端公钥,再生成一个随机数 Random3,再用服务端公钥非对称加密 Random3 生成 PreMaster Key
Client Key Exchange ,上面客户端根据服务器传来的公钥生成了 PreMaster Key,Client Key Exchange 就是将这个 key 传给服务端,服务端再用自己的私钥解出这个 PreMaster Key 得到客户端生成的 Random3。至此,客户端和服务端都拥有 Random1 + Random2 + Random3,两边再根据同样的算法就可以生成一份秘钥,握手结束后的应用层数据都是使用这个秘钥进行对称加密。
- Q:为什么要使用三个随机数呢?
- 这是因为 SSL/TLS 握手过程的数据都是明文传输的,并且多个随机数种子来生成秘钥不容易被暴力破解出来。
Change Cipher Spec(Client),这一步是客户端通知服务端后面再发送的消息都会使用前面协商出来的秘钥加密了
- 该信息用于告诉对方,我已经计算好需要使用的对称密钥了,我们接下来的通信都需要使用该密钥进行加密之后再发送。
- 需要注意的是,发送该信息的一方并不知道对方是否已经计算出密钥。一般由客户端先行发送该信息
Finished 该信息是第一个由TLS记录层协议进行加密保护的信息,双方需要验证对方发送的Finished信息,保证协商的密钥是可用的,保证协商过程中,没有被篡改。验证该verify Data的内容,包括三部分的内容:
- 主密钥
- 标签,客户端的标签是client finished,服务端的标签是server finished
- handshake_messages,包括了所有的握手协议信息
SSL加密建立
64.1 要点解析
-
双向认证和单向认证
- 双向认证可以更好地解决身份冒充的问题
- 但是在一些常见的应用场景中,只有单向认证,如采用https的网站只需要求客户端(浏览器)对服务端的证书进行认证
- 单向认证的场景下,第二阶段服务器不会请求客户端的证书
-
随机数的使用
- 通过使用三个随机数,来确保对称秘钥的随机性(SSL 协议中证书是静态的)
- 使用三个随机数,是因为SSL协议不信任每个主机都能产生完全的随机数,因此通过组合3个随机数,减少对称秘钥被识破的可能性
-
会话秘钥重用
- 避免重建连接时再次进行耗时的SSL/TLS握手过程
- 方法:
- SessionID,客户端和服务端同时维护一个会话ID和会话数据状态;重建连接时双方根据sessionID找到之前的会话密钥实现重用
- SessionTicket,由服务端根据会话状态生成一个加密的ticket,并将key也发给客户端保证两端都可以对其进行解密。该机制相较sessionID的方式更加轻量级,服务端不需要存储会话状态数据,可减轻一定压力
-
证书校验
- 检验数字签名
- 数字签名通过数字摘要算法生成并通过私钥加密传输,对端公钥解密;
- CA链授权检查
- 证书过期及激活时间检查
- 检验数字签名
64.2 公钥证书如何生成?
-
SSL/TLS通过被称为X.509的证书数字文档将网站和公司实体信息绑定到加密密钥来进行工作
-
通过证书将加密密钥和公司组织进行安全关联
-
申请流程
-
服务端将自己的公钥以及要包含在证书中的信息(如域名,组织,电子邮件地址)生成一个CSR文件发送给数字证书认证机构来部署数字签名
-
数字认证机构会检验其中的信息是否正确,如果正确的话就使用自己的私钥来对证书部署数字签名,然后发送给申请人
64.3 HTTPS中间劫持?HTTPS一定是安全的吗?
- 什么是HTTPS劫持?
- 在HTTPS劫持攻击(“中间人攻击”的一种类型)中,网络中的攻击者会伪装成一个网站(例如facebook.com),并且提供带有攻击者公钥的假证书。通常,攻击者无法让任何合法的CA来对一个不受攻击者控制的域名的证书进行签名,因此浏览器会检测并阻止这种攻击行为。
- 但是,如果攻击者可以说服用户安装一个新CA的根证书到浏览器当中,浏览器就会信任攻击者提供的由这个合法CA签发的假证书。通过这些假证书,攻击者可以模仿任何网站,进而可以篡改网站内容、记录用户在网站上的操作或发表的内容等。
- 因此,用户不应该安装根CA证书(受信任证书),因为这样就会将原本安全的通信暴露无遗,导致通信被劫持或篡改而不被用户所感知。
65. 服务端申请证书,客户端验证证书过程详细说一下?
-
证书申请流程
- 服务端将自己的公开秘钥登录至数字证书认证机构
- 数字证书认证机构会用自己的私钥向服务器的公开秘钥部署数字签名并颁发公钥证书
-
证书校验
- 检验数字签名
- 数字签名通过数字摘要算法生成并通过私钥加密传输,对端公钥解密;
- CA链授权检查(证书链验证)
- 通过证书链追溯到可信赖的CA的根。目的是验证签发用户实体证书的CA是否是权威可信的CA
- 因为证书可能不是根CA签发的,可能是下级CA签发的,需要溯源到根CA来验证证书的合法性
- 证书过期及激活时间检查
- 检查有效期
- 域名检查
- 检查证书的域名与当前访问域名是否匹配
- 检验数字签名
-
简单来说,先验证数字签名,判断数据是否在中途遭到恶意修改
-
然后,判断签发数字签名的认证机构是否是权威机构,这个就是通过信任链来进行验证,最终如果能够溯源到根CA的话,那么就是可信的
66. 知道http的长连接吗?举个场景说一下
- 长连接能够复用已经建立的TCP连接
- 因此当打开一个网页的时候,网页包含的一系列资源就可以通过复用同一个TCP连接来进行传输,节省资源开销
- 当一个长连接中,一段时间内没有发送新的消息,那么这个长连接会被断开
67. 为什么计算机网络需要分层?
- 各层之间能够相互独立
- 高层不需要知道底层的工作原理,只需要知道底层的接口能够提供什么服务
- 灵活性好
- 每一层可以根据需要采用最适当的技术来实现
- 易于实现和标准化
- 将复杂的通讯过程划分为不同模块的有序交互过程
- 每个模块能够更加容易设计和实现标准化
68. 不同层的作用介绍一下?
- 物理层
- 计算机间的物理连线,用来传输0,1信号
- 数据链路层
- 对0,1信号进行分组,规定不同组所代表的含义
- 以太网协议
- 网络层
- 用来判断通信双方是否处于同一子网络中,实现不同网络间的通信
- 传输层
- 实现端口到端口通信,将网络中的数据正确传送给不同的应用程序
- 应用层
- 规定了应用程序的数据格式
69. PUT和POST的区别介绍一下?
-
PUT是幂等操作
-
PUT必须明确知道要操作的对象,如果对象不存在就创建对象,否则,将对象完全替换
-
POST不要求幂等
-
POST创建对象时,并不知道要操作的对象,由服务器为新建对象生成唯一URI
-
使用POST修改对象时,一般只是修改对象的部分属性
70. RESTful如何设计URL?
- REST:Resource Representational State Transfe
- 资源表现形式状态转移
- 通过method实现服务端资源的状态改变
- 协议格式
- Method +空格+URL(资源定向)[?过滤条件]+协议版本+操作符
- GET /order/{orderid} :获取指定订单详情
- Method(资源操作行为,改变资源的状态)
- GET :请求服务器特定资源
- POST :服务器创建一个新资源
- PUT :更新服务器资源(整个资源)
- DELETE :服务器删除特定资源
- PATCH :更新服务器上的资源(资源的部分)
71. 访问不了百度的原因?
- 运营商网络出现了问题
- DNS配置错误
- DNS劫持
- DNS服务器返回错误的IP
- 输入爱奇艺的网址,返回优酷的IP
- 服务器错误
- 查看错误代码
72. CDN服务器
-
Content Delivery Network 内容分发网络
-
目的是使得用户能够更快地访问文件
-
CDN服务器通常分布在各地,将源服务器的数据缓存在CDN服务器中
-
当用户要请求数据的时候,会优先去访问就近的CDN服务器。由于服务器的距离较近,因此响应的成功率和速度会大大提升
-
应用场景
-
网站和应用加速
- 对于网站的静态资源,可以直接缓存在CDN服务器上,用户访问可以就近获取
- 但是对于网站的动态资源,则需要回到源服务器进行处理。对于此,CDN会通过优化算法找出最快的传输路径,提高回源效率
-
视频、大文件下载
-
直播加速
- 主播的数据先传送到CDN服务器,然后用户可以访问就近的CDN服务器来获取资源
73. curl的作用?
-
命令行工具,用于请求web服务器
-
常用命令:
-
不带任何参数,默认是get请求
-
-b 能携带cookie
- curl -b 'foo=bar' https://google.com
-
-X POST 发送post请求
- curl -X POST https://google.com/login
-
-d发送携带数据体的post请求,此时可以省略上面的-X POST
-
curl -d'login=emma&password=123' https://google.com/login
-
-
-G参数用来构造 URL 的查询字符串
- curl -G -d 'q=kitties' -d 'count=20' https://google.com/search
- 省略-G会发送post请求
-
-
感觉命令太多了,可能记不住,平常还是使用postman较多
74. cookie
- 默认浏览器关闭的时候被销毁,默认值为负值,如果为正值,那么时间到了就自动失效,0则直接删除
- 通过setMaxAge来设置
75. Session
- 服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。HttpSession
-
Session的实现依赖于cookie
-
session.invalidate(),强制清除session
-
否则,从最后一次访问起,过了30分钟会自动清除,如果中途有访问,则刷新时间
-
存储结构:
- 实际上是一个ConcurrentHashMap
-
存储位置:
- session是存储在servlet容器中的
- 对于Spring WEB应用而言,Context相当于servlet容器的抽象
- 其中对于内嵌Tomcat,默认使用的Context对象就是TomcatEmbeddedContext
- 该context对象继承于StandardContext,其中有一个Manager类型的内部属性
- 该内部属性维护了一个sessions,用于存储session,而这个数据结构为ConcurrentHashMap
- 该map的key一般使用String类型
-
默认失效时间
- 30分钟
- 如果禁用了cookie怎么办?
- url重写技术来传送sessionID
- 或者通过表单隐藏字段来传送sessionID
76. java的socket编程方法
-
ServerSocket
- socket通信的服务端实现,主要用于监听服务端口
- 核心方法:
- bind:绑定端口
- accept:阻塞等待客户端连接
- close:断开连接,释放端口
-
Socket
- 主要用于客户端
- 在创建的时候,需要指定目标IP和端口号
- 常用方法:
- getInputStream,getOutputStream
- close
-
BIO是面向流的,accept、读写数据都会阻塞
-
示例代码
-
服务端
public class Server { public static final Integer port =80; public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(port); System.out.println("服务端监听 "+port+" 端口成功!,等待客户端连接"); while (true){ // 连接成功会返回另外一个socket用于通信 Socket client = serverSocket.accept(); System.out.println("一个新的客户端进来了"); // 另起两个线程进行处理 new WriteHelper(client.getOutputStream(),"连接客户端成功!,可以畅所欲言了").start(); new PrintHelper(client.getInputStream(),"服务端").start(); } } }
- 客户端
public class Client { public static void main(String[] args) throws IOException, InterruptedException { Socket socket = new Socket("127.0.0.1", 80); new WriteHelper(socket.getOutputStream(),"连接服务端成功!,可以畅所欲言了").start(); new PrintHelper(socket.getInputStream(),"客户端").start(); } }
- 读写线程
public class PrintHelper extends Thread{ private InputStream inputStream; private String type; public PrintHelper(InputStream inputStream,String type) { this.inputStream=inputStream; this.type=type; } public void run() { byte[] bytes = new byte[1024]; int length; try { while (true){ if (((length=inputStream.read(bytes))>1)){ // 此处的read方法,如果读到文件结束符(EOF)会返回-1 // 但是如果没有读到会一直阻塞 String s = new String(bytes, 0, length); LocalDateTime nowLocalDate = LocalDateTime.now(); String time = nowLocalDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); System.out.println(" "+time+" "+type+" : "+s); System.out.println("____________________________________________"); } } } catch (IOException e) { e.printStackTrace(); } } } public class WriteHelper extends Thread{ private OutputStream outputStream; public WriteHelper(OutputStream outputStream,String message) { System.out.println(message); System.out.println("============================"); this.outputStream=outputStream; } public void run() { Scanner scanner = new Scanner(System.in); while(true){ String next = scanner.next(); try { outputStream.write(next.getBytes()); outputStream.flush(); } catch (IOException e) { e.printStackTrace(); } } } }
77. ARQ协议是什么?
-
ARQ协议,自动重传请求(Automatic Repeat-reQuest)。该协议是对滑动窗口的一个实现
-
保证TCP可靠性的机制之一
-
停止等待ARQ协议
- 每次发送一个分组后,停止发送并等待接收方响应
- 一段时间内没有收到确认,就重传
- 直到收到确认才会发送下一个分组
- 不足:
- 信道的利用率低,等待时间久
-
连续ARQ协议
- 利用滑动窗口,维护了无需接收方确认也可以继续发送的数据范围
- 提高了信道利用率
78. 服务端出现大量的timewait的原因和解决方法?
-
如何查看
-
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
-
netstat -an |grep TIME_WAIT|wc -l 查看连接数等待time_wait状态连接数
-
通过上述命令可以查看不同状态下的TCP连接的数目
-
问题
- 大量连接处于timewait状态时,新建立TCP连接会报错,错误为“接口已被占用”
- 本地端口数目上限为65536(端口号16位)
-
出现原因
- 大量的短连接
- 高并发短连接
- 在HTTP请求中,如果connection头部的取值设置为close,那么基本都由服务端主动关闭连接
- 服务端处理完请求后主动关闭连接
- 在四挥关闭连接机制中,为了确保确认报文能够正确送达以及本次连接中的报文能全部消亡,会设置timewait状态的时间为2倍的最大报文存活时间(一共大概为4分钟)
- RFC 793中规定MSL为2分钟,实际应用中常用的是30秒,1分钟和2分钟等
- 大量的短连接
-
解决方法
-
客户端:
- connection 设置为 keep-alive,即尽量使用长连接(目前版本的http协议基本上都是长连接)
-
服务端:
- 允许time_wait状态的socket被重用
- net.ipv4.tcp_tw_reuse = 1
- 满足以下条件之一:
- 初始序列号比TW老连接的末序列号大
- 如果使能了时间戳,那么新到来的连接的时间戳比老连接的时间戳大
- 缩减time_wait的时间,设为1MSL
- 增加服务器,进行负载均衡
- 允许time_wait状态的socket被重用
79. 常见应用层、运输层、网络层协议,以及硬件如路由器位于哪一层?
- 应用层
- HTTP,DNS,FTP
- 传输层
- TCP,UDP
- 网络层
- IP,ICMP,路由器,***
- 数据链路层
- 网卡,网桥,交换机
- 物理层
- 中继器,集线器
80. 以太网报文格式?
- 目标地址、源地址
- 网卡的硬件地址(MAC地址),网卡出厂时固化
- 数据
- 以太网帧中数据长度最小为46字节,最大为1500字节
- 不够长需要进行填充,太长了需要进行拆分
- 1500字节是指有效负载的长度,不包括首部长度
81. HTTP和TCP的区别?
- 前者是应用层协议,后者是传输层协议
- HTTP规定每段数据以什么形式表达才能被另外一台计算机理解
- TCP则是规定数据应该怎么传输才能稳定、高效地在计算机之间传输
- 应用层协议的通信依赖于传输层协议
82. HTTP常用首部字段有哪些?
- accept
- 表明客户端浏览器能够接收的媒体类型资源
- accept-encoding
- 表明客户端浏览器接收的编码方式
- accept-language
- 表明客户端浏览器接收的语言
- cache-control
- 控制浏览器缓存
- 如果使用缓存,后续访问相同页面则直接访问缓存
- cookie
- 保存用户会话信息
- refer
- 告诉服务器从哪个页面链接进来
- user-agent
- 浏览器的相关信息
- host
- 请求时服务器的ip和端口号
- Content-Type
- 服务器告诉客户端本次响应体数据格式以及编码格式
- Set-Cookie
- 用于服务器向客户端发送 sessionID
- 服务端向客户端设置cookie
83. 为什么会丢包?
- 接收到包在进行校验的时候出错
- 数据包在网络中超出最大存活时间(ttl)
- 路由器接收分组数量达到上限后,会丢弃多余分组
- 网络断路
84. 301和302的区别有哪些?
-
前者是永久重定向
-
后者是临时重定向
-
对于永久重定向,如果旧的URI保存为书签了,那么永久重定向会根据响应内容将标签的URI修改。临时重定向是不会修改的
-
使用302重定向有可能被判断为网站URL劫持,一个网站A的功能就是临时重定向到网站B,由于网站A的URL可能更加简洁,导致搜索引擎可能会判断网站A的网址更加合适,这时候搜索引擎的结果仍然是网站A,但是所用的网页内容却是网站B的
85. TCP的保活计时器的作用
- TCP的Keepalive,用来检查对方是否有发生异常,如果发生异常就即时关闭连接
- 当连接空闲一段时间,就会发送探测报文,判断对方的响应是否符合预期,如果不正常就主动关闭连接
- 使用SO_KEEPALIVE的套接字选项——相当于心跳包,一段时间没有响应就断开连接
86. 什么是连接?
- 所谓的连接其实只是双方都维护了一个状态,通过每一次通信来维护状态的变更,使得看起来好像有一条线关联了对方。
87. OSI七层模型的含义和作用是什么?
- 物理层
- 包含了网络通信的基础设施
- 包含了节点设备、网络硬件、设备接口、电缆协议等技术,主要功能是用来传输比特流
- 数据链路层
- 对比特流进行分组,规定不同组所代表的含义
- 允许局域网中各个节点彼此相互通信。建立了线路规划、流量控制和错误控制的基础
- 数据的传输格式、节点间流动的数据量大小
- 线路规划
- 流量控制
- 错误控制
- 数据单元是帧,包含帧头、主体和帧尾
- 帧头:通常包括源节点和目的节点的 MAC 地址
- 主体:由要传输的比特组成
- 帧尾:包括错误检测信息
- 帧的大小有限制,限制值为最大传输单元(MTU)
- 网络层
- 判断计算机是否处于同一个网络中,实现不同网络之间的通信
- 数据单元是数据包,会封上IP地址
- 不保证可靠传输
- ARP协议既属于数据链路层,其实也属于网络层,因为IP地址只在这层能够使用,因此需要在该层通过ARP协议定位MAC地址
- 传输层
- 实现端口到端口通信,将网络中的数据正确传送给不同的应用程序
- 会话层
- 会话层负责初始化、维持并终止两个用户应用程序之间的连接
- 这个连接可用是客户端与服务器模型,也可以是请求与响应模型(会话期间可能会有多个请求和响应)
- 例子:RPC调用
- 表示层
- 负责数据格式,比如字符编码与转换,以及数据加密
- 该层负责确保第七层中的用户程序可以成功消费数据,确保最终数据的展示
- 例子:TLS/SSL协议位于第六层,TLS是SSL的继任者
- 应用层
- 负责提供应用程序运行时所需要的服务和功能
- 例子:http,ftp
88. 常用TCP选项有哪些?
- 时间戳选项
- 发送方在报文中放置时间戳,接收方在接收确认中返回该数字,允许发送方为每一个ack计算RTT
- 在复用time_wati接口的时候,如果开启时间戳选项的话,那么新连接的时间戳应该大于旧连接的时间戳
- 最大报文传输字段(MSS)
- TCP数据包每次传输的最大数据分段大小
- 选择确认选线(SACK)
- 快速重传中,接收方用来通告发送发自己的缓存地图
- Window Scale:窗口缩放选项
- 将窗口大小进行缩放
89. 半打开和半关闭的区别?
- 半关闭
- 连接中的一方已经发送了fin报文,等待另外一方发送
- 半打开
- 连接中的一方已经崩溃下线了,另外一端还不知道
90. close-wait过多的原因和解决方法?
-
根本原因是服务端在四挥的最后流程中,没有正确close掉连接
-
也有可能全连接队列过长,还没有处理,就被对方关闭了
-
解决方法
- 检查代码中是否有死循环或者耗时任务导致没有正确close掉连接
91. TCP异常原因有哪些?
- 试图与一个不存在的端口建立连接
- 虽然服务端的进程没有启动,但是操作系统会帮我们自动响应RST给客户端
- 试图与一个不存在的主机上面的某端口建立连接
- 如果connect没有设置超时的话,那么客户端会继续尝试发送syn报文一段时间,直到TCP的保护机制返回错误
- 为了避免多次发送请求带来的延时问题,可以在connect函数中设置超时时间
- server进程阻塞
- server进程无法响应任何请求,连接能正常建立,但是发送的数据会一直保存在缓冲区,永远不会返回结果
- 杀死server
- 其实这个应该不算异常
- 这时候相当于服务端主动关闭连接,走正常的四挥流程
92. 常用的网络工具 telnet、nc、netstat,介绍一下?
-
telnet命令可以用来判断远端服务器指定端口的网络连接是否可达
-
telnet [domainname or ip] [port]
-
nc
- nc -l -p 9090
- -l表示监听
- -p代表要监听的端口
- 这个一般用于服务端,打开某个端口
- nc ip port
- 客户端连接服务端的某个接口
- 连接成功后可以在客户端发送数据给服务端
- nc -l -p 9090
-
该工具同样可以检测服务器的端口的网络连接是否可达
- nc -zv [host or ip] [port]
- -z表示不发送任何数据包,tcp三次握手后自动退出进程
- -v用来输出更多详细信息
- echo ping | nc localhost 6379
- 还可以通过管道的方式将命令发送给redis服务器
- nc -zv [host or ip] [port]
-
netstat
- 部分介绍可以查看linux面试题部分
- 常用的选项就是-anp,显示所有套接字,禁止使用端口别名,显示占用端口的进程
93. tcpdump用法?
-
https://juejin.cn/book/6844733788681928712/section/6844733788849717262
-
抓包工具
- wireshark
- 图形化界面抓包软件,一般Windows下使用较多
- tcpdump
- 命令行网络流量分析工具
- wireshark
-
tcpdump
- -i
- 用来指定网卡,通过ifconfig来查看有哪些网卡可用
- any 的话表示任意网卡
- -n
- 将主机名替换为ip地址
- -nn
- 在前述基础上,不会将端口名替换为协议名,使用端口本来的名称
- -s
- 获取报文中的前多少个字节,一般配合-A使用
- sudo tcpdump -i any -nn port 80 -A -s 500
- 如果想显示全部就使用 -s 0
- -c
- 抓取指定数目的报文
- sudo tcpdump -i any -nn port 80 -c 5
- 只抓5个包就退出了,一般用于交互频繁的服务器上抓包
- -w
- 将数据报文件输出到文件
- sudo tcpdump -i any port 80 -w test.pcap
- 生成的pcap文件可以使用wireshark 打开进行更加详细的分析
- -S
- 显示seq和ack的绝对序号
- 默认显示的是相对序号
- -i
-
tcpdump -i any host 10.211.55.2
- host选项,用来指定要捕获的特定IP的包,这个IP既可以是源地址也可以是目标地址
-
过滤源地址和目标地址
- sudo tcpdump -i any src 10.211.55.10
- 用来抓取主机10.211.55.10 发送的包
- sudo tcpdump -i any dst 10.211.55.10
- 用来抓取主机 10.211.55.10 收到的包
- sudo tcpdump -i any src 10.211.55.10
-
指定端口
- sudo tcpdump -i any port 80
- 只抓取端口80上的包
- 配合dst可以只抓取80端口收到的包
- tcpdump portrange 21-23
- 可以抓取21-23区间上所有端口的流量
- sudo tcpdump -i any port 80
-
指定协议
- sudo tcpdump -i any -nn udp
- 只抓udp的包
- sudo tcpdump -i any -nn udp
-
查看报文内容
- sudo tcpdump -i any -nn port 80 -A
- -A选项,以ASCII 格式查看报文内容
- 常用的HTTP协议中传输的json、html文件都可以使用这个选项
- sudo tcpdump -i any -nn port 80 -X
- 同时使用HEX和ASCII显示报文内容
- sudo tcpdump -i any -nn port 80 -A
-
ASCII
- HEX 和 ASCII
- 复杂过滤器
- 利用布尔运算符组合出复杂的过滤器
- sudo tcpdump -i any host 10.211.55.10 and dst port 3306
- 抓取 ip 为 10.211.55.10 到端口 3306 的数据包
- sudo tcpdump -i any src 10.211.55.10 and not dst port 22
- 抓取源 ip 为 10.211.55.10,目标端口除了22 以外所有的流量
- sudo tcpdump -i any 'src 10.211.55.10 and (dst port 3306 or 6379)'
- 如果用到特殊字符'()'的话,就需要使用单引号将复杂组合条件包起来
- 过滤特殊控制位的包
- tcpdump 'tcp[13] & 4 != 0'
- 过滤RST报文
- tcpdump 'tcp[13] & 18 != 0'
- 过滤SYN+ACK报文
- tcpdump 'tcp[13] & 4 != 0'
94. wireshark用法
- https://juejin.cn/book/6844733788681928712/section/6844733788853895182
- https://blog.csdn.net/wangyiyungw/article/details/82178070
95. session对服务器的压力问题和JWT
-
session在服务端保存用户的会话信息,当用户并发数大的时候,服务端的压力较大
-
可以考虑将部分数据使用cookie的方式存储到客户端浏览器
-
但是cookie本身不支持大量数据存储,而且使用cookie传输会增加网络压力,此时可以使用HTML5技术,使用浏览器的localStorage和sessionStorage来解决问题
-
当然亦可以在后台引入分布式存储机制来解决
-
针对cookie明文保存的不足,引入JSON Web Token(JWT)机制
-
其中Token用来将用户信息保存在客户端,
-
信息本身通过添加数字签名的方式来防止被篡改
-
token的数据一般保存在HTTP Header “X-Auth-Token”中,客户端在拿到数据后就可以将其保存在本地
-
JWT本身由三个部分组成:头部,载荷,签名
-
头部声明签名算法:对称或者非对称,推荐使用非对称
-
载荷可以保存特定用户信息,但是不能保存私密信息,因为是通过明文传输的
-
签名根据头部算法对头部和载荷数据生成一个签名
-
使用JWT可以比较容易地实现单点登录
-
认证中心保存私钥,其它服务保存公钥,当请求携带token访问时,使用公钥进行验证,合理即可使用,否则重定向到认证中心
-
认证功能这部分可以集成到网关API
96. CSRF 跨站点请求伪造 了解吗?
- 攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。
- 大多数用户并不能保证:
- 不能保证关闭浏览器了后,本地的Cookie立刻过期,上次的会话已经结束
- 不能保证登录了一个网站后,不再打开一个tab页面并访问另外的网站
- 由于cookie的信息在访问对应域名的网站的时候会自动携带过去,因此就可以在用户无感的情况下直接攻击目标网站
96.1 有哪些攻击类型?
-
GET类型的CSRF
- GET类型的CSRF利用非常简单,只需要一个HTTP请求,一般会这样利用:在受害者访问含有这个img的页面后,浏览器会自动向
<img src=``"http://bank.example/withdraw?amount=10000&for=hacker" >
-
POST类型的CSRF:
- 这种类型的CSRF利用起来通常使用的是一个自动提交的表单,访问该页面后,表单会自动提交,相当于模拟用户完成了一次POST操作。POST类型的攻击通常比GET要求更加严格一点,但仍并不复杂。任何个人网站、博客,被黑客上传页面的网站都有可能是发起攻击的来源,后端接口不能将安全寄托在仅允许POST上面
-
链接类型的CSRF:
- 这种需要用户点击链接才会触发。这种类型通常是在论坛中发布的图片中嵌入恶意链接,或者以广告的形式诱导用户中招,攻击者通常会以比较夸张的词语诱骗用户点击
96.2 特点是什么?
- 攻击一般发起在第三方网站,而不是被攻击的网站。被攻击的网站无法防止攻击发生
- 攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;而不是直接窃取数据。
- CSRF通常是跨域的,因为外域通常更容易被攻击者掌控。但是如果本域下有容易被利用的功能,比如可以发图和链接的论坛和评论区,攻击可以直接在本域下进行,而且这种攻击更加危险。
96.3 如何防御?
- token;token 验证的 CSRF 防御机制是公认最合适的方案。但若网站同时存在 XSS 漏洞的时候,这个方法也是空谈
- https://www.cnblogs.com/lsdb/p/9591399.html
- token不放cookie(一般form表单加个hidden属性的input标签来存放)csrf就没法获取token,这样我们就可以通过检测发送过来的数据包中是否有正确的token值来决定是否响应请求。
- 可以考虑直接使用sessionid作为token,不过通过隐藏表单项提交作为验证手段
- 验证码;强制用户必须与应用进行交互,才能完成最终请求。此种方式能很好的遏制 csrf,但是用户体验比较差
- Referer check;请求来源限制,此种方法成本最低,但是并不能保证 100% 有效,因为服务器并不是什么时候都能取到 Referer,而且低版本的浏览器存在伪造 Referer 的风险
- 浏览器禁止发送referer或者使用APP就不会有referer
97. XSS攻击是什么?
-
XSS全称cross-site scripting(跨站点脚本),是一种代码注入攻击,是当前 web 应用中最危险和最普遍的漏洞之一。攻击者向网页中注入恶意脚本,当用户浏览网页时,脚本就会执行,进而影响用户,比如关不完的网站、盗取用户的 cookie 信息从而伪装成用户去操作,危害数据安全。
-
举例:
-
存储型XSS(持久性跨站攻击)
- 通过表单输入(比如发布文章、回复评论等功能中)插入一些恶意脚本,并且提交到被攻击网站的服务器数据库中。当用户浏览指定网页时,恶意脚本从数据库中被加载到页面执行,QQ邮箱的早期版本就曾经被利用作为持久型跨站脚本攻击的平台。
- 与反射型 XSS 相比,该类的攻击更具有危害性,因为它影响的不只是一个用户,而是大量用户,而且该种类型还可进行蠕虫传播。