传输层
传输层
内容概括:
- 理解传输层的作用
- 深入理解TCP的各项特性和机制
传输层
负责数据能够从发送端传输到接收端。即点对点的传输。
再谈端口号
端口号(port):
- 标识一个主机上进行通信的不同的应用程序;
- 在TCP/IP协议中,用“源IP”,“源端口号”,“目的IP”,“目的端口号”,“协议号”这样一个五元组来标识一个通信(用 netstat -n 查看);
- 范围划分: (2个字节)
0 - 1023:知名端口号,端口号是固定的。用 “cat /etc/services ”查看
1024 - 65535:操作系统动态分配的端口号,客户端程序的端口号。 - 一个进程可以绑定多个端口号;
- 但一个端口号不能被多个进程绑定, 若非要绑定,可以先绑定再fork(),fork之后子进程就继承了父进程的文件描述符,此时父子进程都关联到了这样一个具体的端口号上了。
netstat [选项]:查看网络状态
pidof [进程名]:通过进程名,查看进程id
UDP协议
UDP协议特点:
- 无连接
- 不可靠
- 面向数据报
- 全双工
UDP使用注意事项:
UDP不能应用于一个单次传输数据量很长的场景,因为一个UDP能传输的最大数据长度只有64K(UDP长度只占了两个字节);
如果非要用UDP进行传输一个超过64K的数据,就要在应用层手动的分包,多次发送,并在接收端手动拼接,但是UDP本身是不可靠传输,所以这样会非常不安全,可能导致部分数据丢失。
基于UDP的应用层协议:
- NFS:网络文件系统
- TFTP:简单文件传输协议
- DHCP:动态主机配置协议
- BOOTP:启动协议
- DNS:域名解析协议
TCP协议
TCP全称为“传输控制协议”,即要对数据的传输进行一个详细的控制。
TCP特点概述:
- 有连接
- 可靠传输
- 面向字节流
TCP协议段格式
- 16位源/目的端口号:表示数据是从哪个进程来,到哪个进程去。
- 32位***/32位确认号:在后面详解
- 4位TCP报头长度:表示该TCP头部有多少个32位bit(有多少个4字节); 所以TCP头部最大长度是15 * 4 =60
- 6位标志位:
ACK: 确认报文段,ACK=1,表示服务器端(客户端)对客户端(服务器端)进行应答。
SYN: 同步报文段,SYN=1,表示尝试和对方建立连接。
FIN: 结束报文段,FIN=1,表示尝试断开连接。
RST: 复位报文段,RST=1,表示尝试和对方重新建立连接。
- 16位校验和:和UDP的类似,都是检验数据传输是否出错。
TCP连接管理机制
在正常情况下, TCP要经过三次握手建立连接, 四次挥手断开连接
几个重要状态:
- ESTABLISHED:表示允许进行数据的读写;
- CLOSE_WAIT:等待服务器代码执行close,关闭连接;
- TIME_WAIT:该状态是为了防止丢包,在此图中,万一丢包,由于TIME_WAIT状态保证客户端连接不会立即释放,就意味着还有机会等待到重传的FIN,所以客户端就可以给对端重传一个ACK,保证了4次挥手的正常完成;
理解TIME_WAIT状态
- TCP协议规定,主动关闭连接的⼀⽅要处于TIME_ WAIT状态,等待两个MSL(maximum segmentlifetime)的时间后才能回到CLOSED状态.
- 我们使⽤Ctrl-C终⽌了server, 所以server是主动关闭连接的⼀⽅, 在TIME_WAIT期间仍然不能再次监听同样的server端⼝;
- MSL在RFC1122中规定为两分钟,但是各操作系统的实现不同, 在Centos7上默认配置的值是60s;
- 可以通过 cat /proc/sys/net/ipv4/tcp_fin_timeout 查看msl的值;
面试题
1. 在服务器端看到了大量的CLOSE_WAIT状态,说明什么问题?
答:说明服务器端代码存在BUG,没有调用close关闭文件描述符,导致处于半关闭状 态。
解决方法:检查代码,将该关的地方调close进行关闭。
2. 若服务器端存在大量的TIME_WAIT状态,说明什么问题?
答:说明服务器主动断开连接,但是当TIME_WAIT连接太多,导致服务器的端口不够用无法处理新的连接。
解决方法:使用setsockopt()设置socket描述符的选项SO_REUSEADDR为1,表示允许创建端口号相同但IP地址不同的多个socket描述符。
确认应答(ACK)机制
连接建立成功之后,发送的每一条数据也有可能会“丢失”,因此就需要确认应答。
TCP将每个字节的数据进行了编号,即为***。
每一个ACK都带有对应的确认***,告诉发送者,我已经收到了哪些数据;下一次你从哪里开始发。
超时重传机制
主机A发送数据给B之后,可能因为网络拥堵等原因,数据无法到达主机B;
如果主机A在一个特定的时间间隔内没有收到B发来的确认应答,就会进行重发。
丢包也可能是ACK丢失了:
主机B会收到很多重复的数据,可以利用***对其进行去重;
此时还需要一个缓冲区来存放接收到数据,由于顺序可能发生错乱,所以也可以利用***进行排序。
TCP为了保证无论在任何环境下都能比较高性能的通信, 因此会动态计算这个最大超时时间.
Linux中(BSD Unix和Windows也是如此), 超时以500ms为一个单位进行控制, 每次判定超时重发的超时时间都是500ms的整数倍.
如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传.
如果仍然得不到应答, 等待 4*500ms 进行重传. 依次类推, 以指数形式递增.
累计到一定的重传次数, TCP认为网络或者对端主机出现异常, 强制关闭连接.
滑动窗口
由于一发一收的方式性能较低,所以采用一次发送多条数据,就可以大大的提高性能(其实是将多个段的等待时间重叠在一起了)
- 窗口大小:指的是无需等待确认应答而可以继续发送数据的最大值;
- 如上图,发送前3个段时,不需要等待任何ACK,直接发送;
- 收到第一个ACK后,滑动窗口向后移动,继续发送第4个段的数据;以此类推;
- 操作系统内核为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答;只有确认应答过的数据,才能从缓冲区删掉;
- 窗口越大,则网络的吞吐率就越高。
丢包情况一:数据包已抵达,但ACK丢了。
这种情况下,部分ACK丢了并不要紧,因为可以通过后续的ACK进行确认。
丢包情况二:数据包直接丢了。
- 当某一段报文段丢失之后,发送端会一直收到这段报文段序号的ACK;
- 如果发送端连续3次接收到同样一个这样的应答,就会将对应的数据重新发送;
流量控制
TCP支持根据接收端的处理能力,来决定发送端的发送速度,这个机制就叫做流量控制。
- 接收端将自己可以接收的缓冲区大小放入TCP首部中的“窗口大小”字段,通过ACK端通知发送端;
- 窗口大小字段越大,说明网络的吞吐量越高;
- 接收端一旦发现自己的缓冲区快满了,就会将窗口大小设置成一个更小的值通知给发送端;
- 发送端接收到这个窗口之后,就会减慢自己的发送速度;
- 如果接收端缓冲区满了,就会将窗口置为0;这时发送方不再发送数据,但是需要定期发送一个窗口探测数据段,使接收端把窗口大小告诉发送端。
拥塞控制
根据当前网络的拥堵程度,来决定发送端的发送速度,这个机制就叫做拥塞控制。
- TCP引入“慢启动”机制,先发少量的数据,探探路,摸清当前的网络拥堵程度,再决定按照多大的速度传输数据;
- “慢启动”只是指初始时慢,但是增长速度非常快;
- 发送开始时,定义拥塞窗口大小为1;
- 每次收到一个ACK应答,拥塞窗口加1;
- 每次发送数据包的时候,就将拥塞窗口和接收端主机反馈的窗口大小作比较,取较小的值作为实际发送的窗口。
- 如上图,当拥塞窗口超过这个慢启动的阈值时,不再按照指数方式增长,而是按照线性方式增长;
- 当TCP开始启动的时候,慢启动阈值等于窗口的最大值;
- 在每次超时重发的时候,慢启动阈值会变成原来的一半,同时拥塞窗口置回1.
拥塞控制,归根结底就是TCP协议想尽可能快的把数据传输给对方,但是又要避免给网络造成太大压力的折中方案。
延迟应答
如果接收数据的主机⽴刻返回ACK应答, 这时候返回的窗⼝可能⽐较⼩.
- 假设接收端缓冲区为1M. ⼀次收到了500K的数据; 如果⽴刻应答, 返回的窗⼝就是500K;
- 但实际上可能处理端处理的速度很快, 10ms之内就把500K数据从缓冲区消费掉了;
- 在这种情况下, 接收端处理还远没有达到⾃⼰的极限, 即使窗⼝再放⼤⼀些, 也能处理过来;
- 如果接收端稍微等⼀会再应答, ⽐如等待200ms再应答, 那么这个时候返回的窗⼝⼤⼩就是1M;
捎带应答
在延迟应答的基础上, 我们发现, 很多情况下, 客户端服务器在应用层也是 “一发一收” 的. 意味着客户端给服务器说了 “How are you”, 服务器也会给客户端回一个 “Fine, thank you”;那么这个时候ACK就可以搭顺风车, 和服务器回应的 “Fine, thank you” 一起回给客户端。
面向字节流
创建一个TCP的socket, 同时在内核中创建一个 “发送缓冲区” 和一个 “接收缓冲区” ;
- 调用write时, 数据会先写入发送缓冲区中;
- 如果发送的字节数太长, 会被拆分成多个TCP的数据包发出;
- 如果发送的字节数太短, 就会先在缓冲区里等待, 等到缓冲区长度差不多了, 或者其他合适的时机发送出去;
- 接收数据的时候, 数据也是从网卡驱动程序到达内核的接收缓冲区;
- 然后应用程序可以调用read从接收缓冲区拿数据;
- 另一方面, TCP的一个连接, 既有发送缓冲区, 也有接收缓冲区, 那么对于这一个连接, 既可以读数据,也可以写数据. 这个概念叫做 “全双工” 。
由于缓冲区的存在, TCP程序的读和写不需要⼀⼀匹配, 例如:
- 写100个字节数据时, 可以调用一次write写100个字节, 也可以调用100次write, 每次写一个字节;
- 读100个字节数据时, 也完全不需要考虑写的时候是怎么写的, 既可以一次read 100个字节, 也可以一次read一个字节, 重复100次;
TCP小结
TCP一方面要保证可靠性,另一方面又要尽可能的提高性能。
保证可靠性的机制有:
- 校验和
- ***(按序到达)
- 确认应答
- 超时重传
- 连接管理
- 流量控制
- 拥塞控制
提高性能的机制有:
- 滑动窗口
- 快速重传
- 延迟应答
- 捎带应答
TCP VS UDP
- TCP用于可靠传输的情况,应用于文件传输,重要状态更新等场景;
- UDP用于对高速传输和实时性要求较高的通信领域,例如视频传输等。并且UDP可用于广播传输。