本文共 3943 字,大约阅读时间需要 13 分钟。
首先解释一段截取的网络数据认识一下。(由a_la_lei解释)
1、-> syn(这一步是初始化发送端的ISN。理论上,它的数据字段没有任何值,消耗的是一个虚字节)
TCP: Sequence number = 4071231308 TCP: Acknowledgement number = 0 2、<- ack syn(初始化接收端的ISN,并对收到的包进行确认。因为确认的方式是累计确认,所以尽管第1步传输了一个虚字节,但ACK仍旧是4071231308+1=4071231309) TCP: Sequence number = 1191340143 TCP: Acknowledgement number = 4071231309 3、-> ack(回应第2步的确认。因为第1步消耗的是一个虚字节,所以理论上Seq应该仍旧是4071231308,但由于协议的具体实现略有不同,这里又在虚字节上加1变成4071231309。仍旧是累计确认。) TCP: Sequence number = 4071231309 TCP: Acknowledgement number = 1191340144 4、-> ack push 登录信息(载荷包。因为第3步仅是一个确认包,它没有包含任何有效数据,所以这里的Seq仍旧是4071231309。仍旧是对第2步确认) TCP: Sequence number = 4071231309 TCP: Acknowledgement number = 1191340144 5、<- ack(仅仅是一个确认包。仍旧是根据累计确认原则对第4步确认,ACK等于4071231309+有效载荷=4071231337) TCP: Sequence number = 1191340144 TCP: Acknowledgement number = 4071231337 6、<- ack push 回应信息(载荷包。因为第5步仅仅是一个确认包,所以这里不消耗任何序号,Seq仍旧是1191340144。ACK仍旧是对第4步的确认) TCP: Sequence number = 1191340144 TCP: Acknowledgement number = 4071231337 7、-> ack(仅仅是一个确认包。仍旧是根据累计确认原则对第6步确认,ACK等于1191340144+有效载荷=1191340217) TCP: Sequence number = 4071231337 TCP: Acknowledgement number = 1191340217 8、<- ack push 第二次回应信息(载荷包。因为仍旧有数据要发送,按第7步给予的ACK来设置此包的Seq。此包的Ack仍旧是4071231337) TCP: Sequence number = 1191340217 TCP: Acknowledgement number = 4071231337 本流程需要知道的几个规则: 规则1、累计确认。接收端对收到的载荷包(数据字段有值的TCP包),回应一个确认包,确认号是所收到包的TCP数据字段最后一个字节+1。 规则2、捎带确认。载荷包必须捎带确认字段。这样可以减少网络流量。 规则3、虚字节。有些数据包(ACK)不携带任何数据,所以不消耗序列号,也就是说仍旧保持不变。uip中,序号的操作流程
三次握手:第一次 第二次 第三次
seqno:1713796940 2957476497 1713796941 ackno:0 1713796941 2957476498 SYN = 1 ACK = 0 SYN = 1 ACK = 1 SYN = 0 ACK = 1 seqno:32位序号,表示在这个报文段中的的第一个数据字节。:我发送的数据段第一个字节的序列号是。 ackno:32位确认序号包含发送确认的一端所期望收到的下一个序号。:我希望下次接收到的数据段第一个字节的序列号。u8_t snd_nxt[4]; // 下一次发送的起始字节的序列号
u8_t rcv_nxt[4]; // 上一次接收起始字节的序列号u8_t iss /TCP初始化序列号
u8_t uip_acc32[4]; /临时变量无意义/ u8_t BUF->seqno[1]...[4]; //TCP里的32位序号 u8_t BUF->ackno[1]...[4]; //TCP里的32位确认序号void uip_add_rcv_nxt(u16_t n) // 功能:(u32_t)rcv_nxt = (u32_t)rcv_nxt + n
{}1.主动链接中的应用:
uip_connect() // 主动发起链接函数 { conn->snd_nxt[0] = iss[0]; // 用于第一次握手的seqno conn->snd_nxt[1] = iss[1]; conn->snd_nxt[2] = iss[2]; conn->snd_nxt[3] = iss[3]; } found:中主动链接部分 if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) { // 收到了ACK帧,同时有待确认的数据; uip_add32(uip_connr->snd_nxt, uip_connr->len); // 计算下一次发送的第一个字节的序列号 // uip_connr->len 用于记录本次发送的字节数 // 在第三次握手中uip_connr->len = 1 if(BUF->ackno[0] == uip_acc32[0] && BUF->ackno[1] == uip_acc32[1] && BUF->ackno[2] == uip_acc32[2] && BUF->ackno[3] == uip_acc32[3]) { uip_connr->snd_nxt[0] = uip_acc32[0]; uip_connr->snd_nxt[1] = uip_acc32[1]; uip_connr->snd_nxt[2] = uip_acc32[2]; uip_connr->snd_nxt[3] = uip_acc32[3]; } }uip_connr->rcv_nxt[0] = BUF->seqno[0]; // 用于第三次握手的ackno,将收到的
uip_connr->rcv_nxt[1] = BUF->seqno[1]; // 第二次握手中的seqno+1赋值给第三 uip_connr->rcv_nxt[2] = BUF->seqno[2]; // 次握手中的ackno uip_connr->rcv_nxt[3] = BUF->seqno[3]; uip_add_rcv_nxt(1); // uip_connr->rcv_nxt[3] = uip_connr->rcv_nxt[3]+12.被动连接中应用:
found_listen: uip_connr->tcpstateflags = SYN_RCVD;uip_connr->snd_nxt[0] = iss[0]; // 第二次握手用的seqno赋值,该值是有咱定。
uip_connr->snd_nxt[1] = iss[1]; uip_connr->snd_nxt[2] = iss[2]; uip_connr->snd_nxt[3] = iss[3];/* rcv_nxt should be the seqno from the incoming packet + 1. */
uip_connr->rcv_nxt[3] = BUF->seqno[3]; // 将对方第一次握手发送的seqno+1赋值给 uip_connr->rcv_nxt[2] = BUF->seqno[2]; // 第二次握手用的ackno uip_connr->rcv_nxt[1] = BUF->seqno[1]; uip_connr->rcv_nxt[0] = BUF->seqno[0]; uip_add_rcv_nxt(1);3.平时交互信息中的应用:
计算seqno的值跟主动链接中的应用-found:中主动链接部分代码重合,不在多说。 计算ackno: uip_add_rcv_nxt(1 + uip_len); // uip_connr->rcv_nxt+1+uip_len,其中uip_len是接收到的数据长度。最后都要应用:
BUF->ackno[0] = uip_connr->rcv_nxt[0]; BUF->ackno[1] = uip_connr->rcv_nxt[1]; BUF->ackno[2] = uip_connr->rcv_nxt[2]; BUF->ackno[3] = uip_connr->rcv_nxt[3]; BUF->seqno[0] = uip_connr->snd_nxt[0]; BUF->seqno[1] = uip_connr->snd_nxt[1]; BUF->seqno[2] = uip_connr->snd_nxt[2]; BUF->seqno[3] = uip_connr->snd_nxt[3];写入序号值。
====
http://blog.21ic.com/user1/4861/archives/2009/59995.html
转载地址:http://rebkb.baihongyu.com/