lwip之数据收发流程_3
生活随笔
收集整理的這篇文章主要介紹了
lwip之数据收发流程_3
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
// 只會被tcp_process函數(shù)調(diào)用,用于進(jìn)一步完成對輸入報文的處理,具體來說,該函數(shù)主要是完成輸入報文的冗余截斷,管理unacked、unsent、ooseq三張鏈表void tcp_receive(struct tcp_pcb *pcb){struct tcp_seg *next;struct tcp_seg *prev, *cseg;struct pbuf *p;s32_t off;s16_t m;u32_t right_wnd_edge;?? ?// 本地發(fā)送窗口右邊界u16_t new_tot_len;int found_dupack = 0;?? ?// 重復(fù)ack標(biāo)志,置1表示是重復(fù)ack?? ?// 首先檢測報文是否包含ACK標(biāo)志if (flags & TCP_ACK){right_wnd_edge = pcb->snd_wl2 + pcb->snd_wnd;?? ?// 獲取本地發(fā)送窗口右邊界// 有3種情況可以導(dǎo)致本地發(fā)送窗口更新if (TCP_SEQ_LT(pcb->snd_wl1, seqno)||?? ??? ??? ??? ??? ??? ??? ??? ?// snd_wl1小于新seqno,說明對方有發(fā)來數(shù)據(jù)(pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno))||?? ?// snd_wl1等于新seqno且snd_wl2小于新ackno,說明對方?jīng)]有發(fā)送數(shù)據(jù),只是在收到數(shù)據(jù)后發(fā)送一個確認(rèn)(pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) ?? ??? ??? ?// snd_wl2等于新ackno且snd_wnd小于報文首部的窗口通告wnd,說明我方?jīng)]有發(fā)數(shù)據(jù)過去,但被對方告知接收窗口變大?? ?{pcb->snd_wnd = tcphdr->wnd;?? ??? ?// 更新本地發(fā)送窗口大小?? ?,跟對方發(fā)來的接收窗口通告匹配pcb->snd_wl1 = seqno;?? ??? ??? ?// 更新接收到的序號pcb->snd_wl2 = ackno;?? ??? ??? ?// 更新接收到的確認(rèn)號// 如果發(fā)送窗口非0,且探察開啟if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0){pcb->persist_backoff = 0;?? ?// 停止窗口探察}}// 判斷是否是一個重復(fù)的ACK,需要滿足5個條件// 1.如果ackno小于等于lastack,即沒有確認(rèn)新數(shù)據(jù)if (TCP_SEQ_LEQ(ackno, pcb->lastack)) ?? ??? ??? ??? ??? ??? ?{pcb->acked = 0;?? ??? ?// 沒有確認(rèn)新數(shù)據(jù),那么acked為0// 2.如果報文段中沒有數(shù)據(jù)if (tcplen == 0){// 3.本地發(fā)送窗口沒有更新if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){// 4.如果重傳定時器正在運(yùn)行,即本地有數(shù)據(jù)正等待被確認(rèn)if (pcb->rtime >= 0){// 5.如果ackno等于lastackif (pcb->lastack == ackno){// 此時可以確定這是一個重復(fù)的ack,說明報文發(fā)生了丟失found_dupack = 1;// 該ack被重復(fù)收到的次數(shù)自增if (pcb->dupacks + 1 > pcb->dupacks)++pcb->dupacks;// 如果該ack重復(fù)收到超過3次,說明發(fā)生了擁塞if (pcb->dupacks > 3){if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd){pcb->cwnd += pcb->mss;}}// 如果該ack重復(fù)第3次收到,執(zhí)行快速重傳算法else if (pcb->dupacks == 3){tcp_rexmit_fast(pcb);}}}}}// 如果沒有確認(rèn)新數(shù)據(jù)但又不屬于重復(fù)ackif (!found_dupack){pcb->dupacks = 0;?? ??? ?// 將ack重復(fù)收到的次數(shù)清0}}// 如果是正常情況的ACK,lastack+1<=ackno<=snd_nxtelse if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){// 如果控制塊處于快速重傳狀態(tài)?? ?,則關(guān)閉重傳狀態(tài)、擁塞功能?? ?if (pcb->flags & TF_INFR){pcb->flags &= ~TF_INFR;pcb->cwnd = pcb->ssthresh;}pcb->nrtx = 0;?? ??? ??? ??? ??? ??? ??? ??? ?// 重傳次數(shù)清0pcb->rto = (pcb->sa >> 3) + pcb->sv;?? ??? ?// 復(fù)位重傳超時時間pcb->acked = (u16_t)(ackno - pcb->lastack);?? ?// 更新acked字段為被確認(rèn)的已發(fā)送數(shù)據(jù)長度pcb->snd_buf += pcb->acked;?? ??? ??? ??? ??? ?// 更新可用的發(fā)送空間pcb->dupacks = 0;?? ??? ??? ??? ??? ??? ??? ?// 將ack重復(fù)收到的次數(shù)清0pcb->lastack = ackno;?? ??? ??? ??? ??? ??? ?// 更新接收到的ackno// 如果處于TCP連接已經(jīng)建立狀態(tài),調(diào)整擁塞算法功能模塊if (pcb->state >= ESTABLISHED){if (pcb->cwnd < pcb->ssthresh){if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd){pcb->cwnd += pcb->mss;}}else{u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);if (new_cwnd > pcb->cwnd){pcb->cwnd = new_cwnd;}}}// 遍歷unacked隊列,將所有數(shù)據(jù)編號小于等于ackno的報文段移除while (pcb->unacked != NULL && TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked), ackno)){ ??? ?// 將滿足要求的報文從unacked鏈表取出next = pcb->unacked;pcb->unacked = pcb->unacked->next;// 如果該報文包含F(xiàn)IN標(biāo)志,意味著當(dāng)前收到的ACK對FIN做了確認(rèn),則acked字段減1,即不需要提交上層使知道FIN被對方成功接收if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)){pcb->acked--;}pcb->snd_queuelen -= pbuf_clen(next->p);?? ??? ?// 釋放被該報文占用的發(fā)送空間tcp_seg_free(next);?? ??? ??? ??? ??? ??? ??? ??? ?// 釋放被該報文占用的tcp報文段}// 當(dāng)所有滿足要求的報文段移除成功后,判斷unacked隊列是否為空if(pcb->unacked == NULL)pcb->rtime = -1;?? ?// 若為空,關(guān)閉重傳定時器elsepcb->rtime = 0;?? ??? ?// 否則復(fù)位重傳定時器pcb->polltmr = 0;?? ??? ?// 復(fù)位輪詢定時器}?? ??? ?// 如果該ACK既不是重復(fù)ACK,又不是正常ACK,則acked字段清0,即該ACK不確認(rèn)任何已發(fā)送數(shù)據(jù)else{pcb->acked = 0;}// 遍歷unsent隊列,將所有數(shù)據(jù)編號小于等于ackno的報文段移除// 這是因為對于需要重傳的報文段,lwip直接將它們掛在unsent隊列上,所以收到的ACK可能是對已超時報文段的確認(rèn)while (pcb->unsent != NULL && TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)){// 將滿足要求的報文從unsent鏈表取出next = pcb->unsent;pcb->unsent = pcb->unsent->next;// 如果該報文包含F(xiàn)IN標(biāo)志,意味著當(dāng)前收到的ACK對FIN做了確認(rèn),則acked字段減1,即不需要提交上層使知道FIN被對方成功接收if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)){pcb->acked--;}pcb->snd_queuelen -= pbuf_clen(next->p);?? ??? ?// 釋放被該報文占用的發(fā)送空間tcp_seg_free(next);?? ??? ??? ??? ??? ??? ??? ??? ?// 釋放被該報文占用的tcp報文段}// RTT計算,暫略if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)){m = (s16_t)(tcp_ticks - pcb->rttest);m = m - (pcb->sa >> 3);pcb->sa += m;if (m < 0) {m = -m;}m = m - (pcb->sv >> 2);pcb->sv += m;pcb->rto = (pcb->sa >> 3) + pcb->sv;?? ?pcb->rttest = 0;}}// 如果該輸入報文還包含了數(shù)據(jù),則要繼續(xù)對數(shù)據(jù)進(jìn)行處理if (tcplen > 0){// 如果seqno + 1 <= rcv_nxt <= seqno + tcplen - 1,意味著收到的數(shù)據(jù)區(qū)域頭部有無效數(shù)據(jù)(收到的數(shù)據(jù)有部分處于本地左側(cè)接收窗口外),需要截斷數(shù)據(jù)頭if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){off = pcb->rcv_nxt - seqno;?? ??? ??? ??? ??? ??? ??? ?// 需要截掉的數(shù)據(jù)長度p = inseg.p;?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?// 獲取收到的報文段的pbuf鏈表頭// 判斷需要截斷的長度是否超出了第一個pbuf中存儲的數(shù)據(jù)長度if (inseg.p->len < off){new_tot_len = (u16_t)(inseg.p->tot_len - off);?? ?// 截斷重復(fù)數(shù)據(jù)后的有效數(shù)據(jù)長度// 如果超出,則需要遍歷pbuf鏈表,依次摘除數(shù)據(jù),直到最后一個包含摘除數(shù)據(jù)的pbufwhile (p->len < off){off -= p->len;?? ??? ??? ??? ??? ??? ??? ??? ?// 剩余摘除長度p->tot_len = new_tot_len;?? ??? ??? ??? ??? ?// 更新當(dāng)前pbuf中的數(shù)據(jù)總長,p->len = 0;?? ??? ??? ??? ??? ??? ??? ??? ??? ?// 因為數(shù)據(jù)被摘除,所以當(dāng)前pbuf中的數(shù)據(jù)分長清0p = p->next;?? ??? ??? ??? ??? ??? ??? ??? ?// 指向下一個pbuf}// 處理最后一個包含摘除數(shù)據(jù)的pbuf,就是調(diào)整數(shù)據(jù)指針略過摘除數(shù)據(jù)pbuf_header(p, (s16_t)-off);}else{// 如果未超出,則調(diào)整第一個pbuf中的數(shù)據(jù)指針略過摘除數(shù)據(jù)pbuf_header(inseg.p, (s16_t)-off);}inseg.len -= (u16_t)(pcb->rcv_nxt - seqno);?? ?// 更新TCP報文段數(shù)據(jù)總長inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;?? ?// 更新TCP頭中的seqno,指向接收窗口頭位置}else{// 如果seqno < rcv_nxt,意味著seqno+tcplen-1 < rcv_nxt,說明這是個完全重復(fù)的報文段if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){tcp_ack_now(pcb);?? ??? ?// 只回復(fù)一個ACK給對方(這里是否應(yīng)該直接返回不再運(yùn)行下去)}}// 如果數(shù)據(jù)起始編號在接收窗口內(nèi)if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd - 1)){// 如果該報文數(shù)據(jù)處于接收起始位置,意味著該報文是連續(xù)到來的if (pcb->rcv_nxt == seqno){tcplen = TCP_TCPLEN(&inseg);?? ??? ?// 更新該報文的總數(shù)據(jù)長度// 如果總長大于接收窗口大小,就需要做尾部截斷處理,這里包含對FIN和SYN兩種標(biāo)志的不同處理結(jié)果,注意體會if (tcplen > pcb->rcv_wnd){// 如果TCP頭中帶FIN標(biāo)志,清除FIN標(biāo)志,因為對方還有數(shù)據(jù)要發(fā)過來if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN){TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN);}inseg.len = pcb->rcv_wnd;?? ??? ?// 根據(jù)接收窗口調(diào)整數(shù)據(jù)長度// 如果TCP頭中帶SYN標(biāo)志,報文段數(shù)據(jù)長度減1if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN){inseg.len -= 1;}pbuf_realloc(inseg.p, inseg.len);?? ?//? 因為數(shù)據(jù)被截斷,pbuf中的參數(shù)需要相應(yīng)調(diào)整tcplen = TCP_TCPLEN(&inseg);?? ??? ?// 再次更新該報文的總數(shù)據(jù)長度}// 如果無序報文段隊列ooseq上存在報文段if (pcb->ooseq != NULL){// 判斷當(dāng)前有序報文段的TCP頭中是否帶FIN標(biāo)志if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN){// 如果該有序報文段帶FIN標(biāo)志,意味著單向TCP連接結(jié)束// 不可能再從對方收到新的報文段,ooseq隊列中的報文段沒有成為有序報文段可能,只能作廢while (pcb->ooseq != NULL){struct tcp_seg *old_ooseq = pcb->ooseq;pcb->ooseq = pcb->ooseq->next;tcp_seg_free(old_ooseq);}}else{next = pcb->ooseq;// 遍歷ooseq鏈表,刪除序號被當(dāng)前有序報文段完全覆蓋的報文段while (next && TCP_SEQ_GEQ(seqno + tcplen,next->tcphdr->seqno + next->len)){// 如果這些即將被刪除的報文段帶FIN標(biāo)志且當(dāng)前有序報文段不帶SYN標(biāo)志if (TCPH_FLAGS(next->tcphdr) & TCP_FIN &&(TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0){TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN);?? ?// 在當(dāng)前有效報文段的TCP頭中添加FIN標(biāo)志tcplen = TCP_TCPLEN(&inseg);?? ??? ??? ?// 再次更新該報文的總數(shù)據(jù)長度}prev = next;next = next->next;tcp_seg_free(prev);}// 如果當(dāng)前有序報文段尾部與ooseq中的報文段存在部分重疊?? ?if (next && TCP_SEQ_GT(seqno + tcplen,next->tcphdr->seqno)){inseg.len = (u16_t)(next->tcphdr->seqno - seqno);?? ?// 截斷當(dāng)前有序報文段尾部的重疊部分,得到有效部分長度// 如果當(dāng)前有序報文段TCP頭中帶SYN標(biāo)志,報文段數(shù)據(jù)長度減1if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN){inseg.len -= 1;}pbuf_realloc(inseg.p, inseg.len);?? ??? ??? ?//? 因為數(shù)據(jù)被截斷,pbuf中的參數(shù)需要相應(yīng)調(diào)整tcplen = TCP_TCPLEN(&inseg);?? ??? ??? ??? ?// 再次更新該報文的總數(shù)據(jù)長度}pcb->ooseq = next;}}pcb->rcv_nxt = seqno + tcplen;?? ?// 更新下一個期望接收到的序號,也就是接收窗口左邊界pcb->rcv_wnd -= tcplen;?? ??? ??? ?// 更新當(dāng)前可用接收窗口tcp_update_rcv_ann_wnd(pcb);?? ?// 更新公告窗口// 如果該有序報文段中存在數(shù)據(jù)if (inseg.p->tot_len > 0){recv_data = inseg.p;?? ??? ?// 將全局指針recv_data指向報文段中的數(shù)據(jù)pbufinseg.p = NULL;}// 如果該有序報文段的TCP頭中帶FIN標(biāo)志if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN){recv_flags |= TF_GOT_FIN;?? ??? ?// 則在報文處理結(jié)果變量recv_flags添加TF_GOT_FIN標(biāo)志}// 遍歷ooseq隊列,取出所有有序的報文段// (通過比較ooseq隊列中報文段的seqno和當(dāng)前TCP控制塊中保存的rcv_nxt來判定該報文段是否有序)while (pcb->ooseq != NULL && pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt){cseg = pcb->ooseq;seqno = pcb->ooseq->tcphdr->seqno;?? ?// 更新序號pcb->rcv_nxt += TCP_TCPLEN(cseg);?? ?// 更新下一個期望接收到的序號pcb->rcv_wnd -= TCP_TCPLEN(cseg);?? ?// 更新當(dāng)前可用接收窗口tcp_update_rcv_ann_wnd(pcb);?? ??? ?// 更新公告窗口// 如果該有序報文段中存在數(shù)據(jù),則通過全局指針recv_data向上層提交數(shù)據(jù)if (cseg->p->tot_len > 0){// 判斷全局指針recv_data是否為空if (recv_data){// 如果不為空,意味著有更早的數(shù)據(jù)準(zhǔn)備向上提交pbuf_cat(recv_data, cseg->p);?? ?// 將當(dāng)前數(shù)據(jù)pbuf掛到recv_data指向的數(shù)據(jù)鏈表的尾部}else{// 如果為空,直接將當(dāng)前數(shù)據(jù)pbuf賦給recv_datarecv_data = cseg->p;}cseg->p = NULL;}// 如果該有序報文段的TCP頭中帶FIN標(biāo)志if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN){recv_flags |= TF_GOT_FIN;?? ??? ?// 則全局變量recv_flags添加TF_GOT_FIN標(biāo)志// 如果當(dāng)前TCP處于ESTABLISHED狀態(tài),則變成CLOSE_WAIT狀態(tài)if (pcb->state == ESTABLISHED){pcb->state = CLOSE_WAIT;}}pcb->ooseq = cseg->next;tcp_seg_free(cseg);}// 以上都執(zhí)行完畢后,向源端返回一個ACK,此處其實只是先在TCP控制塊中添加ACK標(biāo)志tcp_ack(pcb);}// 如果該報文數(shù)據(jù)不處于接收起始位置,意味著該報文不是有序的else{// 首先向源端返回一個立即ACKtcp_send_empty_ack(pcb);// 然后將該報文段放入ooseq隊列if (pcb->ooseq == NULL){// 如果ooseq為空,則拷貝該報文段到新開辟的報文段空間,并將新開辟報文段作為ooseq起始單元pcb->ooseq = tcp_seg_copy(&inseg);}else{prev = NULL;?? ?// 定義為ooseq鏈表中上一個報文段,這里首先清空// 遍歷ooseq隊列,選擇合適位置插入該報文段for(next = pcb->ooseq; next != NULL; next = next->next){// 依次比較兩個報文段的起始序號seqno,如果相等if (seqno == next->tcphdr->seqno){// 繼續(xù)比較兩個報文段的數(shù)據(jù)長度if (inseg.len > next->len){// 如果輸入報文段數(shù)據(jù)長度更長// 拷貝該報文段到新開辟的報文段空間cseg = tcp_seg_copy(&inseg);// 插入ooseq鏈表if (cseg != NULL){// 如果不是ooseq上的第一個報文段if (prev != NULL){prev->next = cseg;?? ?// 插入ooseq鏈表的上一個報文段之后}// 如果是第一個else{pcb->ooseq = cseg;?? ?// 直接替換原有的第一個}tcp_oos_insert_segment(cseg, next);?? ?// 處理好插入后與原有的下一個報文段的影響,簡單來說,就是切掉冗余,釋放內(nèi)存}break;?? ?// 退出循環(huán)?? ??? ??? ??? ??? ??? ??? ?}else{// 如果輸入報文段數(shù)據(jù)長度更短,則直接丟棄,并退出循環(huán)break;}}// 如果不相等else{// 如果是ooseq上的第一個報文段if (prev == NULL){// 如果該報文段的起始序號大于要插入的報文段起始序號if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)){cseg = tcp_seg_copy(&inseg);?? ??? ??? ?// 拷貝要插入的報文段到新開辟的報文段空間if (cseg != NULL){pcb->ooseq = cseg;?? ??? ??? ??? ??? ?// 將新報文段插到ooseq第一個位置tcp_oos_insert_segment(cseg, next);?? ?// 處理好插入后與原有的第一個報文段的影響}break;?? ??? ?// 退出循環(huán)}}// 如果不是第一個else{// 如果待插入報文段起始序號在前一個和后一個報文段起始序號之間if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)){cseg = tcp_seg_copy(&inseg);?? ?// 拷貝要插入的報文段到新開辟的報文段空間if (cseg != NULL){// 如果與前一個報文段有數(shù)據(jù)重合if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)){prev->len = (u16_t)(seqno - prev->tcphdr->seqno);?? ?// 截斷前一個報文段尾部pbuf_realloc(prev->p, prev->len);?? ??? ??? ??? ??? ?// 因為數(shù)據(jù)被截斷,pbuf中的參數(shù)需要相應(yīng)調(diào)整}prev->next = cseg;?? ??? ??? ??? ??? ?// 將新報文段插入前一個報文段之后tcp_oos_insert_segment(cseg, next);?? ?// 處理好插入后與原有的下一個報文段的影響}break;}}// 如果已經(jīng)是ooseq上的最后一個報文段// 且待插入的報文段起始序號大于該報文起始序號(其實函數(shù)運(yùn)行到這里該條件必然成立)if (next->next == NULL && TCP_SEQ_GT(seqno, next->tcphdr->seqno)){// 如果該報文的TCP頭中有FIN標(biāo)志,則直接丟棄待插入的報文段,退出循環(huán)if (TCPH_FLAGS(next->tcphdr) & TCP_FIN){break;}next->next = tcp_seg_copy(&inseg);?? ?// 拷貝要插入的報文段到新開辟的報文段空間,并插在隊列尾部// 如果新插入的報文段不為空if (next->next != NULL){// 如果與前一個報文段有數(shù)據(jù)重合if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)){next->len = (u16_t)(seqno - next->tcphdr->seqno);?? ?// 截斷前一個報文段尾部pbuf_realloc(next->p, next->len);?? ??? ??? ??? ??? ?// 因為數(shù)據(jù)被截斷,pbuf中的參數(shù)需要相應(yīng)調(diào)整}// 如果新插入的報文段數(shù)據(jù)長度超出了當(dāng)前接收窗口大小if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd){// 如果新插入的報文段的TCP頭中有FIN標(biāo)志if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN){TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN);?? ?// 去掉TCP頭中的FIN標(biāo)志}next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno;?? ?// 根據(jù)接收窗口大小調(diào)制新插入的報文段數(shù)據(jù)長度pbuf_realloc(next->next->p, next->next->len);?? ??? ??? ?// 因為數(shù)據(jù)被截斷,pbuf中的參數(shù)需要相應(yīng)調(diào)整tcplen = TCP_TCPLEN(next->next);?? ??? ??? ??? ??? ??? ?// 再次更新該報文的總數(shù)據(jù)長度}}break;}}prev = next;?? ?// 以上都不滿足,則遍歷ooseq鏈表中下一個}}}}// 如果數(shù)據(jù)不在接收范圍內(nèi)else{tcp_send_empty_ack(pcb);?? ?// 直接向源端返回一個立即確認(rèn)ACK}}// 如果輸入的報文段中不包含數(shù)據(jù)else{// 且序號位于接收窗口之內(nèi)if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){tcp_ack_now(pcb);?? ??? ?// 回一個ACK}}}err_t tcp_output(struct tcp_pcb *pcb){struct tcp_seg *seg,*useg;u32_t wnd,snd_nxt;if(tcp_input_pcb == pcb){return ERR_OK;?? ?}wnd = LWIP_MIN(pcb->snd_wnd,pcb->cwnd);seg = pcb->unsent;if(pcb->flags & TF_ACK_NOW && (seg = NULL || ntohl(seg->tcphdr->seqno)? )){}}
?
總結(jié)
以上是生活随笔為你收集整理的lwip之数据收发流程_3的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Cortex-M3 内部寄存器
- 下一篇: 记一次lwip中 遇到 pcb == p