TCP协议 & TCP首部

说明:TCP协议十分复杂和重要,对于个人已经掌握的点在本文就不在详述。

常识:服务器和客户端判断对方是否已经关闭连接的方法:read函数返回0

[1]TCP头部结构、TCP头部选项结构

在这里插入图片描述

TCP选项详解:
在这里插入图片描述

[2]紧急指针和带外数据OOB

[A]概念

  1. 带外数据用于通知对方本端发送的重要事件
  2. 因为是重要事件,因此带外数据具有更高的优先级:无论发送缓冲区中是否有普通数据,带外数据都会立即发送
  3. 实际应用中,带外数据很少用
  4. UDP没有实现带外数据,TCP没有真正的带外数据,不过TCP利用头部中的URG和16位的紧急指针两个字段,给应用程序提供了一种紧急方式。

[B]相关API

  1. send/recv函数的flag设置为MSG_OOB,表示发送或接收紧急数据。
  2. 带外标记
    (1)Linux内核检测到TCP紧急标志时,将通知应用程序有带外数据到来,需要接受。通知有两种方式:I/O复用产生异常事件、SIGURG信号。
    (2)int sockmark(int fd);
    应用程序可以使用sockmark判断套接字fd下一个被读取到的数据是否是带外数据。如果是,返回1,此时可以使用recv+MSG_OOB读取带外数据;否则,返回0。

[C]TCP发送带外数据过程

在这里插入图片描述

[D]TCP接收带外数据过程

case1:TCP接收带外数据过程(默认接收方式)
先检查TCP头部的紧急指针标志URG;然后根据紧急指针所指向的位置确定带外数据的位置,并将它读入一个特殊的缓存中(带外缓存)。
说明:这个缓存只有一个字节,称为带外缓存。如果上层应用程序没有及时将带外数据从带外缓存中读走,则后序的带外数据到来时将会覆盖带外缓存中的数据。
case2:TCP接收带外数据过程(设置SO_OOBLINE选项)
给TCP连接设置SO_OOBLINE选项,则带外数据将和普通数据一样被TCP模块存放在TCP接收缓冲区中(而不是放在带外缓存中),此时应用程序需要向读取普通数据一样来读取带外数据。==那么问题来了:这种情况下如何区分带外数据和普通数据呢?==显然,紧急指针可以用来指出带外数据的位置,socket编程接口也提供了系统调用来识别带外数据。

[E]内核通知应用程序带外数据到达的方法

  1. select的异常事件触发:带外数据到来时,select的异常事件将触发
  2. 使用SIGURG信号捕捉:当带外数据到来时,将产生SIGURG信号
void handler(int signo)
{
	//使用recv+MSG_OOB读取带外数据
}

int main()
{
	//注册信号SIGURG以及信号处理函数handler
	signal(SIGURG,handler);
	//使用SIGURG信号之前,必须设置socket的宿主进程或进程组
	fcntl(connfd, F_SETOWN, getpid());
}

[3]使用tcpdump观察TCP连接的建立和关闭

可以看到:在telnet登陆和退出的过程中,使用tcpdump可以抓取到三次握手和四次挥手的数据包
在这里插入图片描述

[4]TCP的11种状态、三次握手/四次挥手、TIME_WAIT/CLOSE_WAIT

参考《TCP的11种状态、三次握手/四次挥手、TIME_WAIT/CLOSE_WAIT》一文https://blog.csdn.net/weixin_36750623/article/details/84951261

[5]复位报文段RST: flags [R.]

收到RST段的一方应该关闭连接或重新建立连接,而不能回应这个复位报文段

产生复位报文段的3种情况

1.访问/connect一个不存在的端口

在这里插入图片描述

2.向处于TIME_WAIT状态的端口发起连接请求时

当客户端向服务器的某个端口发起连接,而服务器的该端口处于TIME_WAIT状态时,客户端会收到RST段

3.异常终止连接

初始时,A和B已经建立了连接
(1)但是A使用socket选项SO_LINGER向B发送RST段,此时A缓冲区中所有排队等待的数据将都会丢弃(详细请看socket套接字选项详解的SO_LINGER)
(2)B收到A发送来的RST段后,将异常的断开A和B之间的连接

4.处理半打开连接

初始时,A和B已经建立了连接
(1)A关闭或者异常终止了连接,但是B没有收到FIN段(比如网络发生了故障)。此时AB双方还维持着原来的连接,而A即使重启,也没有该连接的任何信息,我们将这种状态称为半打开状态。处于半打开状态的连接称为半打开连接。
(2)B向A中写入数据,则A将回复RST段给B

总结一句话:向处于半打开状态的连接写入数据,则对方将回应一个RST段。

[6]TCP超时重传

  1. A向B发送TCP报文段&&开启重传定时器,假设A没有收到B对该TCP报文段的ACK,那么A将在重传定时器到时时,重传TCP报文段。
  2. 每次重传的超时时间都增加一倍,默认是0.2s、0.4s、0.8s、1.6s… …
  3. 当重传次数等于允许的最大重传次数时,底层的IP和ARP开始接管,直到A端放弃连接为止

Linux有两个重要参数与TCP超时重传相关:/proc/sys/net/ipv4/tcp_retries1(在底层IP接管之前TCP最少执行的重传次数)、/proc/sys/net/ipv4/tcp_retries2(连接放弃前TCP最多可以执行的重传次数)

[7]拥塞控制

  1. TCP模块还有一个重要任务,就是提高网络利用率,降低丢包率,保证网络资源对每条数据流的公平性。这就是所谓的拥塞控制。
  2. 拥塞控制包括4部分:
    慢启动
    拥塞避免
    快重传
    快恢复

[8]TCP数据流

TCP之间交换应用程序数据,数据按照长度分为两种:交互数据、成块数据。

交互数据成块数据
仅包含很少的字节成块数据的长度=TCP报文段允许的最大数据长度
对实时性要求高对传输效率要求高
telnet、sshFTP
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值