1.参考教材和源码
- 《TCP/IP详解 卷1:协议》--第17章170页开始
- 《TCP/IP详解 卷2:实现》--第24章636页开始
- 乾颐堂现任明教教主 TCPIP协议详解
- linux内核源码tcp部分
2.TCP:传输控制协议
2.1TCP服务
TCP提供的是一种面向连接的(全双工),可靠的字节流服务,具体表现在:
- 应用数据被分割成TCP认为最适合发送的数据块。如180字节的数据块,切分成6段发送,每个TCP报文的数据块的大小为30个字节,IP和UDP不切分,给多少发多少
- 发出一段数据后,将开启一个定时器。如果不能在规定时间内收到对端的确认报文则重新发送
- 对端收到发送端的数据后,将发送一个确认。但这个确认不是立即发送,通常推迟几分之一秒,因为可能对端也有数据发送,打包一起发送节省资源
- 检验首部的校验和CRC
- tcp可对收到的数据重新排列。因为TCP被包裹在IP报文中,IP数据报传输是无序的
- IP数据报可能会重复,TCP的接收端必须丢弃重复报文
- TCP还能提供浏览控制,具体表现在滑动窗口
另外TCP对字节流不做任何解释,不管传输的数据是字节流还剩ASCII字符等,需要两端自己协商(将对数据的解释权丢给应用层)
2.2TCP报文首部
image- 首先我们关注前8个字节,即源端口号sport,目标端口号dport和序列号seq,这三个能确定一个TCP报文。linux编程中的socket就是指ip+端口。
四元组:源目(发送方和目标)ip、源目端口
五元组:源目ip、源目端口、协议号
- 确认序列号(seq p2)为源报文序列号(seq p1)加上数据长度。若数据100位则seq p2=seq p1+100;若不包含数据,则说明该报文p1是用于建立连接/断开连接等功能的,后6位标志位其中一位被置为1(也有可能是多个标志位被置为1),相当于该报文携带的数据是标志位,则seq p2 = seq p1+1(标志位占1位)
- 窗口大小用于流量控制,一般表示接收方的缓存大小,但是目前2^16-1大小的窗口大小已经不够我们当代的通讯使用,所以还会与一个窗口扩大因子挂钩。
- 6个标志比特位。主要常用4个ack确认、rst重连、syn建立连接、fin完成发送
2.3查看首部源码
tcp头部tcphdr结构体被定义在头文件tcp.h中
struct tcphdr {
__be16 source;//源端口 16位1-65535
__be16 dest;//目标端口 16位
__be32 seq;//序列号 32位
__be32 ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u16 res1:4,//保留位 位域写法,表示分别占该字节的多少位
doff:4,//数据偏移量
fin:1,
syn:1,
rst:1,
psh:1,
ack:1,
urg:1,
ece:1,
cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
__u16 doff:4,
res1:4,
cwr:1,
ece:1,
urg:1,
ack:1,
psh:1,
rst:1,
syn:1,
fin:1;
#else
#error "Adjust your <asm/byteorder.h> defines"
#endif
__be16 window; //窗口大小
__sum16 check; //校验和
__be16 urg_ptr;//紧急指针
};
上面doff和res1有两种排序是因为大端和小端的原因
其中数据类型,后面的数字表示其占用的位大小
typedef unsigned short u16;
typedef unsigned short _u16;
typedef unsigned int u32;
typedef u32 _be32
typedef u16 _be16
typedef _u16 _sum16
image.png
网友评论