要实现用户态协议栈,必须要搞懂TCP,TCP 11个状态、滑动窗口、拥塞控制、定时器等等。
要使用用户态协议栈,内核提供的epoll就不起作用了,我们需要自己实现用户态的epoll。epoll内部涉及到一个回调的时机,回调的作用是将红黑树中的节点添加进就绪队列,具体在epoll原理里面会具体讲解。搞清楚TCP的11个状态,我们就明白应该在什么时机进行回调了。
TCP状态转换图
在前面的[posix与网络协议栈](Build software better, together api和网络协议栈.md)中,已经介绍了tcp的状态转换。可以结合tcp状态转换图一起看。
TCP状态保存在哪里?保存在TCB中,即TCP PCB,协议控制块。里面包含了socket信息,以及sendbuffer,recvbuffer。TCB保存了从listen到time_wait的所有状态。
用户态TCP协议栈实现
前面实现了UDP协议栈,TCP协议栈实现也是类似的,但是比UDP要复杂很多。
TCP头定义
seq num初始值是多少,到达最大值(2^32 - 1)后怎么样, 会越界吗?
seq num初始值是一个随机值,之后累加。到达最大值后又从0开始计算,不会越界。
seq num指的是包的数量,还是字节数量?
计算的时候,使用的都是字节数。
TCP的包是什么意思?TCP头为什么没有包长?
TCP前后两个包都有序号,就可以计算出包的长度。
ack num = seq num + 包长。
header length是4bit,最大值是15,单位是4个字节,所以TCP头最大时15*4 = 60字节。没有option的话,TCP头是20字节,header length值就是5。
window size,能够接收数据的最大容量。
urgent pointer, 如果URG位置1,就是告诉对端从这个位置开始的数据,要马上处理。
struct tcphdr {
unsigned short sport;
unsigned short dport;
unsigned int seqnum;
unsigned int acknum;
unsigned char hdrlen_resv;
unsigned char flag;
unsigned short window;
unsigned short checksum;
unsigned short urgent_pointer;
unsigned int options[0];
};