1. 分层网络协议
- OSI七层网络协议:物理层,数据链路层,网络层,传输层(TCP/UDP),会话层,表示层,应用层
- TCP/IP协议分层(可以理解为OSI的一种实现):网络接口层,网络层,传输层(TCP/UDP),应用层
2. TCP通信协议简介:
- 面向连接的、可靠的、基于字节流的 传输层通信协议
- 将应用层的数据流分割成报文段并发送给目标节点的TCP层
- 数据包都有序号,对方收到则发送ACK确认,未收到则重传
- 使用校验和来校验数据在传输过程中是否有误
- 报文头中的ACK(确认序号标志),SYN(同步序号,用于建立连接过程)
3. TCP建立连接的三次握手
- 第一次:建立连接时,客户端发送
SYN包(syn=j)
到服务器,并进入SYS_SEND
状态,等待服务器确认; - 第二次:服务器收到
SYN包
,必须确认客户的SYN(ack=j+1)
,同时自己也发送一个SYN包(syn=k)
,即SYN+ACK包
,此时服务器进入SYN_RECV
状态; - 第三次:客户端收到
SYN+ACK包
,向服务器发送确认包ACK(ack=k+1)
,此包发送完毕,客户端和服务端进入ESTABLISHED
状态,完成三次握手。
4. 为什么需要三次握手
- 为了初始化Sequence Number的初始值(通信双方要互相通知对方自己的Sequence Number,要作为以后数据通信的序号,以保证接收到的数据不会因为网络传输问题而乱序,TCP会用这个序号拼接数据)
5. 首次握手的隐患—SYN超时
- 服务端收到客户端的SYN,回复SYN-ACK的时候未收到ACK确认
- 服务端不断尝试(重发SYN-ACK)直至超时,Linux默认等待63秒才断开连接(默认重试5次,重试间隔1s开始,每次翻倍,即1+2+4+8+16+32=63)
- 可能遭受SYN Flood的风险(syn攻击,又称为ddos攻击)
6. 什么是SYN Flood攻击
- 客户端恶意的向某个服务器端口发送大量的SYN包,则可以使服务器打开大量的半开连接,分配TCB,从而消耗大量的服务器资源,同时也使得正常的连接请求无法被相应。而攻击发起方的资源消耗相比较可忽略不计。
- SYN Flood是当前最流行的DoS(拒绝服务攻击)与DDoS(分布式拒绝服务攻击)的方式之一。
7. Linux针对SYN Flood的防护措施
- SYN队列满后,通过tcp_syncookies参数回发SYN Cookies
- 若为正常连接则客户端会回发SYN Cookies,直接建立连接
8. 建立连接后,客户端出现故障怎么办(保活机制)
- 向对方发送保活探测报文,如果未收到响应则继续发送
- 尝试次数达到保活探测树仍未收到响应则中断连接
9. TCP终止连接的四次挥手(以客户端主动为例)
- 第一次:客户端发送一个
FIN(seq=u)
,用来关闭客户端到服务器的数据传送,客户端进入FIN_WAIT_1
状态; - 第二次:服务器收到
FIN
,发回一个ACK(ack=u+1)
,确认序号为收到的序号+1(和SYN一样,一个FIN将占用一个序号),服务端进入CLOSE_WAIT
状态; - 第三次:服务端发送一个
FIN(seq=w)
,用来关闭服务端到客户端的数据传送,服务端进入LAST_ACK
状态; - 第四次:客户端收到
FIN
,发回一个ACK(ack=w+1)
,将确认序号设置为收到序号+1,客户端进入TIME_WAIT
状态,服务端进入CLOSED
状态,完成四次挥手。
10. 存在TIME_WAIT状态的原因
- 保证TCP全双工连接的可靠释放,确保有足够时间让对方收到ACK包
- 避免新旧来凝结混淆,使旧数据包在网络中因过期而失效
11. 为什么需要四次挥手
- 因为全双工,发送方和接收方都需要FIN报文和ACK报文
12. 服务器出现大量CLOSE_WAIT状态的原因
- 对方关闭socket连接,我方忙于读或写,没有及时关闭连接
- 检查代码,特别是释放资源的代码
- 检查配置,特别是处理请求的线程配置
13. UDP简介
- 面向非连接
- 不维护连接状态,支持同时向多个客户端传输相同消息
- 数据包报头只有8个字节,额外开销小
- 吞吐量只受限于数据生成速率、传输速率以及机器性能
- 尽最大努力交付,不保证可靠性,不需要维持复杂的链接状态表
- 面向报文,不对应用程序提交的报文信息进行拆分或者合并
14. TCP和UDP的区别
- 面向连接 vs 无连接
- 可靠性和有序性 vs 不保证
- 全双工的字节流 vs 全双工的数据报
- 效率低 vs 速度快
- 重量级 vs 轻量级
15. Http协议简介
- 基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等),Hyper Text Transfer Protocol(超文本传输协议)的缩写。
- 简单快速:客户向服务器请求服务时,只需传送请求方法(GET、HEAD、POST等)和路径。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
- 灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
- 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
- 无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快
- 支持B/S及C/S模式。
16. HTTP 请求/响应的步骤
- 客户端连接到Web服务器
- 一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接。例如,https://chaooo.github.io。
- 发送HTTP请求
- 通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成。
- 服务器接受请求并返回HTTP响应
- Web服务器解析请求,定位请求资源。服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。
- 释放连接TCP连接
- 若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求;
- 客户端浏览器解析HTML内容
- 客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。然后解析每一个响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。
17. 在浏览器地址栏键入URL,按下回车之后会经历以下流程:
- 浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;
- 解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立TCP连接;
- 浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器;
- 服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器;
- 释放 TCP连接;
- 浏览器将该 html 文本并显示内容;
18. HTTP之状态码
- 状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别:
- 1xx:指示信息–表示请求已接收,继续处理
- 2xx:成功–表示请求已被成功接收、理解、接受
- 3xx:重定向–要完成请求必须进行更进一步的操作
- 4xx:客户端错误–请求有语法错误或请求无法实现
- 5xx:服务器端错误–服务器未能实现合法的请求
- 常见状态码:
- 200 OK //客户端请求成功
- 400 Bad Request //客户端请求有语法错误,不能被服务器所理解
- 401 Unauthorized //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
- 403 Forbidden //服务器收到请求,但是拒绝提供服务
- 404 Not Found //请求资源不存在,eg:输入了错误的URL
- 500 Internal Server Error //服务器发生不可预期的错误
- 503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常
19. HTTPS和HTTP的区别:
- https协议需要到CA申请证书(收费),http不需要。
- https密文传输,http明文传输。
- http使用80端口,https默认使用443端口。
- https = http + 加密 + 认证 + 完整性保护
20. Socket简介
Socket是对TCP/IP协议的抽象,是操作系统对外开发的接口
基于tcp协议的编程模型
- 服务器:
- 创建ServerSocket类型的对象并提供端口号;
- 等待客户端的连接请求,调用accept方法;
- 使用输入输出流进行通信;
- 关闭Socket;
- 客户端:
- 创建Socket类型的对象并提供服务器的通信地址和端口号;
- 使用输入输出流进行通信;
- 关闭Socket;
- 服务器:
基于udp协议的编程模型
- 主机A(接收方):
- 创建DatagramSocket类型的对象,并提供端口号;
- 创建DatagramPacket类型的对象,用于接收发来的数据;
- 从Socket中接收数据,调用**receive()**方法;
- 关闭Socket并释放有关的资源;
- 主机B(发送方)
- 创建DatagramSocket类型的对象;
- 创建DatagramPacket类型的对象,并提供接收方的IP地址和端口号;
- 通过Socket发送数据,调用**send()**方法;
- 关闭Socket并释放有关的资源;
- 主机A(接收方):