Skip to content

Latest commit

 

History

History
134 lines (69 loc) · 6.37 KB

tcpip.md

File metadata and controls

134 lines (69 loc) · 6.37 KB

TCP/IP

TCP 与 UDP 区别?

1、前者面向连接,可靠,但速度慢;适用于如文件传输、重要状态的更新等;后者面向无连接,不可靠,但速度快;适用于如视频传输、实时通信等

2、前者点对点;后者支持一对一、一对多、多对一、多对多

3、后者不支持拥塞控制、流量控制

4、前者报文长度动态调整;首部20字节;后者面向报文,不合并,不拆分;首部8字节(源端口,目的端口,数据长度,校验和)

三次握手

首先,接收方调用 listen() 处于 LISTEN 状态,

发送方调用 connect() 发送一个 SYN 包,转为 SYN_SNET 状态,

接收方接收到后发送 SYN + 相应的 ACK 包,转为 SYN_RCVD 状态,

发送方收到后转为 ESTABLISHED 状态,接着再发送相应的 ACK 包,

接收方收到后也转为 ESTABLISHED 状态,

至此,全双工通信的可靠连接建立完成。

为什么TCP建立连接要三次握手?

1、可以限制半连接的数量

2、因为TCP是双向的可靠连接,三次是保证可靠的理论最小次数

首先得回答三次握手的目的是同步连接双方的序列号和确认号并交换 TCP 窗口大小信息。然后可以回答为什么两次握手不行,两次握手可能因为丢包而出现死锁,假设在两次握手场景中,C向S发送请求,S收到并发送确认请求给C,这时候S认为连接已经建立,并开始发送数据给C,但是那个确认请求丢包了,C不认为请求建立了,C当然会拒绝接受S发送来的数据,并且再去请求连接。这样,一个资源就死锁了。最后回答握手当然可以四次五次一直握下去,但三次已经够了,就没有必要了。总结下来一句话,主要目的防止在网络发生延迟或者丢包的情况下浪费资源。

3、如果只有两次,一个发送一个应答,那么攻击着可以采用IP欺骗,发动SYN洪水攻击,并且服务端还都是ESTABLISHED状态

四次挥手

首先,发送方主动调用 close() 发起连接断开请求,发送一个 FIN 包,进入 FIN_WAIT_1 状态,

接收方收到后转为 CLOSE_WAIT 状态,

接收方发送相应的 ACK 包,发送方收到后转为 FIN_WAIT_2 状态,

接收方调用 close(), 发送一个 FIN 包,转为 LAST_ACK 状态,

送方收到后转为 TIME_WAIT 状态,等待 2MSL 时间后关闭连接,

发送方发送相应的 ACK 包,接收方收到后正式关闭连接。

  • 为什么TCP断开连接要四次挥手?

TCP通信是一种全双工的通信,可以进行半关闭。因此需要在客户端和服务器端分别进行关闭

TIME_WAIT 意义?

1、可靠地实现TCP全双工连接的终止。如果这个ACK丢失,对方将超时重传重新发出最终的FIN。因此A端必须维护状态信息(TIME_WAIT)允许它重发最终的ACK。如果A端不维持TIME_WAIT状态,而是处于CLOSED 状态,那么A端将响应RST分节,B端收到后将此分节解释成一个错误;

2、允许老的重复分节在网络中消逝。2MSL后,这次连接的所有报文都会消失,不会影响下一次连接;

服务器产生大量 TIME_WAIT 原因和解决办法?

由于通常是服务器主动关闭连接。且一个 MSL 大约是 2分钟,十分影响效率。可以通过修改系统配置文件相关项,如下:

1、开启socket重用,允许将TIME_WAIT的socket重新用于TCP连接

2、开启快速回收

怎么做的长连接?

1、TCP自带,发送keepalive包

第一次探测在两小时没有数据传送后

变量保活时间、保活时间间隔、保活探测数, 默认设置为 7200 秒(2小时)、75000 毫秒(75秒0)、8(FreeBSD)或 9(MacOSX).

Windows 保活时间间隔为 1000 毫秒(1秒), 保活探测数为 10.

没有经过应用层的请求, Linux 系统不会提供保活功能, 但是一个特殊库会被预先载入(即载入普通共享库之前), 从如图实现该功能.

针对保活机制的攻击主要有两种:一种是使系统长时间地维护不必要的会话资源, 另一种是获得系统隐藏的一些信息.

因为默认情况下 TCP 不会对保活报文进行加密, 所以保活探测报文和确认报文都有可能被利用. 而对于应用层的保活机制, 这些报文都会被加密.

2、应用层制定协议,发送heartbeat包

应用层心跳必不可少?

1、操作系统崩溃导致机器重启, 没有机会发送 FIN 分节

2、服务器硬件故障导致机器重启, 也没有机会发送 FIN 分节

3、并发连接数很高时, 操作系统或进程如果重启, 可能没有机会断开全部连接, 即 FIN 分节可能出现丢包, 但没有机会重试

4、网络故障, 连接双方能得知这一情况的唯一方案是检测心跳超时

为什么 TCP keepalive 不能代替应用层心跳?

心跳除了说明进程还在、网络通畅, 更重要的是表明应用程还能正常工作;

而 TCP keepalive 由操作系统负责探查, 即使进程死锁或阻塞, 操作系统也会如常收发 TCP keepalive 消息, 对方无法得知这一异常.

心跳设计关键?

(高置信度与低反应时间不可兼得)

进程 C 依赖于 S, 则一般 S 为 sender, C 为 receiver.

1、通常 sender 的发送周期和 receiver 的检查周期相同, 为 T; timeout 时间一般为 2T

2、T 越小, 开销越大; T 越大, receiver 检测到故障的延迟也就越大

3、心跳信息应该包含发送方的标识符; 建议也包含当前负载, 便于客户端做负载均衡

4、如果 sender 和 receiver 之间有其他消息中转进程, 那么还应该加上 sender 的发送时间, 防止消息在传输过程中堆积而导致假心跳

5、要在工作线程中发送, 不要单独起一个”心跳线程”, 防止伪心跳(防止工作线程死锁或阻塞时还在发送心跳)

6、与业务信息用同一个连接, 不要单独用”心跳连接”, 防止伪心跳(如果验证的不是收发业务数据的 TCP 连接畅通则意义不大)

讲一下 TCP 的拥塞控制?

TCP 粘包、半包问题?

这是因为 RCP 是流式协议,需要人为划分边界。

解决方法: 1、固定包长的数据包 2、以指定字符(串)为包的结束标志 3、包头+包体格式

编程函数

报头