lwip之数据收发流程_2
生活随笔
收集整理的這篇文章主要介紹了
lwip之数据收发流程_2
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
三.傳輸層(這里主要講TCP)TCP連接的建立過(guò)程(三次握手):1. 客戶端發(fā)送一個(gè)SYN標(biāo)志置1的TCP數(shù)據(jù)報(bào),握手包中指明源端口和目的端口,同時(shí)告知客戶端初始序號(hào)seqno_client2. 當(dāng)服務(wù)器接收到該數(shù)據(jù)包并解析后,也發(fā)回一個(gè)SYN標(biāo)志置1的數(shù)據(jù)報(bào)作為應(yīng)答,應(yīng)答中包含服務(wù)器端初始序號(hào)seqno_server,同時(shí)將ACK標(biāo)志置1,將確認(rèn)序號(hào)設(shè)置為seqno_client+13. 當(dāng)客戶端接收到服務(wù)端的SYN應(yīng)答包,會(huì)再次產(chǎn)生一個(gè)握手包,包中ACK標(biāo)志置1,確認(rèn)序號(hào)設(shè)置為seqno_server+1TCP連接的斷開(kāi)過(guò)程(四次握手):1. 當(dāng)客戶端應(yīng)用程序主動(dòng)執(zhí)行關(guān)閉操作時(shí),客戶端會(huì)向服務(wù)器發(fā)送一個(gè)FIN標(biāo)志置1的報(bào)文段,用來(lái)關(guān)閉從客戶端到服務(wù)器的數(shù)據(jù)傳送,該報(bào)文段序號(hào)字段為seqno_client2. 當(dāng)服務(wù)器接收到這個(gè)FIN報(bào)文段后,返回一個(gè)ACK報(bào)文,確認(rèn)序號(hào)為seqno_client+1,當(dāng)客戶端收到這個(gè)ACK后,從客戶端到服務(wù)器方向的連接就斷開(kāi)了3. 服務(wù)器TCP向其上層應(yīng)用程序通過(guò)客戶端的端口操作,這會(huì)導(dǎo)致服務(wù)器應(yīng)用程序關(guān)閉它的連接,同樣,此時(shí)一個(gè)FIN置1的報(bào)文段將被發(fā)往客戶端,該報(bào)文段序號(hào)字段為seqno_server4. 當(dāng)客戶端收到這個(gè)FIN報(bào)文段后,也會(huì)返回一個(gè)ACK作為響應(yīng),確認(rèn)序號(hào)為seqno_server+1,從服務(wù)器到客戶端方向的連接也就被斷開(kāi)了******************************************************************************************************************************************************************************************************?? ?lwip一共定義了11種TCP狀態(tài):enum tcp_state{CLOSED?? ??? ?= 0,?? ?// 沒(méi)有連接LISTEN?? ??? ?= 1,?? ?// 服務(wù)器進(jìn)入偵聽(tīng)狀態(tài),等待客戶端的連接請(qǐng)求SYN_SENT?? ?= 2,?? ?// 連接請(qǐng)求已發(fā)送,等待確認(rèn)SYN_RCVD?? ?= 3,?? ?// 已收到對(duì)方的連接請(qǐng)求ESTABLISHED = 4,?? ?// 連接已建立FIN_WAIT_1?? ?= 5,?? ?// 程序已關(guān)閉該連接FIN_WAIT_2?? ?= 6,?? ?// 另一端已接受關(guān)閉該連接CLOSE_WAIT?? ?= 7,?? ?// 等待程序關(guān)閉連接CLOSING?? ??? ?= 8,?? ?// 兩端同時(shí)收到對(duì)方的關(guān)閉請(qǐng)求LAST_ACK?? ?= 9,?? ?// 服務(wù)器等待對(duì)方接受關(guān)閉操作TIME_WAIT?? ?= 10,?? ?// 關(guān)閉成功,等待網(wǎng)絡(luò)中可能出現(xiàn)的剩余數(shù)據(jù)}兩條最經(jīng)典的TCP狀態(tài)轉(zhuǎn)換路徑:1.第一條路徑描述了客戶端申請(qǐng)建立連接與斷開(kāi)連接的整個(gè)過(guò)程:CLOSED ————————> SYN_SENT ————————> ESTABLISHED ————> FIN_WAIT_1 ————> FIN_WAIT_2 ——————> TIME_WAIT ——> CLOSED主動(dòng)打開(kāi)/syn?? ??? ??? ??? ?syn+ack/ack?? ??? ??? ??? ??? ?? /fin?? ??? ??? ??? ??? ?ack/?? ??? ??? ??? ?fin/ack2.第二條路徑描述了服務(wù)器建立連接與斷開(kāi)連接的整個(gè)過(guò)程:CLOSED ————————> LISTEN ————————> SYN_RCVD ————> ESTABLISHED ————————> CLOSE_WAIT ————> LAST_ACK ————> CLOSED被動(dòng)打開(kāi)/?? ??? ??? ??? ??? ?syn/syn+ack?? ??? ??? ??? ?ack/?? ??? ??? ??? ??? ?fin/ack?? ??? ??? ??? ??? ? ??? ?/fin?? ??? ??? ??? ?ack/******************************************************************************************************************************************************************************************************?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?lwip使用一個(gè)tcp_hdr的結(jié)構(gòu)體來(lái)描述tcp協(xié)議包頭:struct tcp_hdr{u16_t src;?? ??? ??? ??? ??? ?// 源端口u16_t dest;?? ??? ??? ??? ??? ?// 目的端口u32_t seqno;?? ??? ??? ??? ?// 序號(hào),用來(lái)標(biāo)識(shí)從TCP發(fā)送端到接收端的數(shù)據(jù)字節(jié)流u32_t ackno;?? ??? ??? ??? ?// 確認(rèn)序號(hào),是發(fā)送確認(rèn)的一段所期望收到的下一個(gè)序號(hào)u16_t _hdrlen_rsvd_flags;?? ?// 包含4位TCP包頭長(zhǎng)(通常為5*4,即本結(jié)構(gòu)體大小)、6個(gè)標(biāo)志位(URG、ACK、PSH、RST、SYN、FIN)u16_t wnd;?? ??? ??? ??? ??? ?// 窗口大小字段,表示還能接收的字節(jié)數(shù),實(shí)現(xiàn)流量控制u16_t chksum;?? ??? ??? ??? ?// 16位整個(gè)TCP報(bào)文校驗(yàn)和,包含了TCP頭和TCP數(shù)據(jù),由發(fā)送端計(jì)算并由接收端驗(yàn)證u16_t urgp;?? ??? ??? ??? ??? ?// 緊急指針,暫略}******************************************************************************************************************************************************************************************************?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?lwip使用一個(gè)tcp_pcb控制塊來(lái)描述一個(gè)TCP連接(lwip實(shí)際定義了2種TCP控制塊,一種專門用于描述處于LISTEN狀態(tài)的連接,另一種用于描述處于其他狀態(tài)的連接):struct tcp_pcb{IP_PCB;?? ??? ??? ??? ??? ??? ?// 該宏描述了連接的IP相關(guān)信息,主要包含源IP、目的IP兩個(gè)重要字段?? ?// 這部分是2種類型TCP控制塊都具有的字段?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?struct tcp_pcb *next;?? ??? ?// 指向下一個(gè)tcp_pcb控制塊的鏈表指針enum tcp_state state;?? ??? ?// TCP連接的狀態(tài),如上所述共11種u8_t prio;?? ??? ??? ??? ??? ?// 該控制塊的優(yōu)先級(jí),可用于回收低優(yōu)先級(jí)控制塊void *callback_arg;?? ??? ??? ?// 指向用戶自定義數(shù)據(jù),在函數(shù)回調(diào)時(shí)使用tcp_accept_fn accept;?? ??? ?// 連接accept時(shí)回調(diào)函數(shù)u16_t local_port;?? ??? ??? ?// 綁定的本地端口u16_t remote_port;?? ??? ??? ?// 遠(yuǎn)程端口u8_t flags;?? ??? ??? ??? ??? ?// 控制塊狀態(tài)、標(biāo)志字段,描述了當(dāng)前控制塊的特性,各位的含義如下宏定義#define TF_ACK_DELAY?? ?0x01?? ?// 延遲發(fā)送ACK#define TF_ACK_NOW?? ??? ?0x02?? ?// 立即發(fā)送ACK#define TF_INFR?? ??? ??? ?0x04?? ?// 連接處于快重傳狀態(tài)#define TF_TIMESTAMP?? ?0x08?? ?// 連接的時(shí)間戳選項(xiàng)已使能#define TF_RXCLOSED ?? ?0x10?? ?// 因TCP連接斷開(kāi)導(dǎo)致RX關(guān)閉#define TF_FIN?? ??? ??? ?0x20?? ?// 應(yīng)用程序已關(guān)閉該連接#define TF_NODELAY?? ??? ?0x40?? ?// 禁止Nagle算法#define TF_NAGLEMEMERR?? ?0x80?? ?// 本地緩沖區(qū)溢出// 接收相關(guān)字段u32_t rcv_nxt;?? ??? ??? ??? ?// 期望接收的下一個(gè)序號(hào),也即是本地將要反饋給對(duì)方的ACK的序號(hào),也是本地接收窗口的左邊界u16_t rcv_wnd;?? ??? ??? ??? ?// 當(dāng)前接收窗口大小,會(huì)隨著數(shù)據(jù)的接收與遞交動(dòng)態(tài)變化u16_t rcv_ann_wnd;?? ??? ??? ?// 將向?qū)Ψ酵ǜ娴拇翱诖笮?#xff0c;也會(huì)隨著數(shù)據(jù)的接收與遞交動(dòng)態(tài)變化u32_t rcv_ann_right_edge;?? ?// 上一次窗口通告時(shí)窗口的右邊界值// 時(shí)間相關(guān)字段u32_t tmr;?? ??? ??? ??? ??? ?// 其它各計(jì)數(shù)器都基于tmr的值來(lái)實(shí)現(xiàn)?? ??? ?u8_t polltmr, pollinterval;?? ?// 這兩個(gè)字段用于周期性調(diào)用一個(gè)函數(shù),polltmr會(huì)周期性增加,當(dāng)超過(guò)pollinterval時(shí),poll函數(shù)會(huì)被調(diào)用s16_t rtime;?? ??? ??? ??? ?// 重傳定時(shí)器,當(dāng)大于rto的值時(shí)則重傳報(bào)文u16_t mss;?? ??? ??? ??? ??? ?// 對(duì)方可接收的最大報(bào)文大小// RTT估計(jì)相關(guān)的參數(shù)u32_t rttest;u32_t rtseq;s16_t sa, sv;s16_t rto;?? ??? ??? ??? ??? ?// 重傳超時(shí)時(shí)間,使用上面3個(gè)RTT參數(shù)計(jì)算出來(lái)u8_t nrtx;?? ??? ??? ??? ??? ?// 重傳次數(shù)// 快速重傳與恢復(fù)相關(guān)字段u32_t lastack;?? ??? ??? ??? ?// 接收到的上一個(gè)確認(rèn)序號(hào),也就是最大確認(rèn)序號(hào)u8_t dupacks;?? ??? ??? ??? ?// 上述最大確認(rèn)序號(hào)被重復(fù)收到的次數(shù)?? ?// 阻塞控制相關(guān)參數(shù)u16_t cwnd; ??? ??? ??? ??? ?// 連接當(dāng)前的阻塞窗口大小u16_t ssthresh;?? ??? ??? ??? ?// 擁塞避免算法啟動(dòng)閾值// 發(fā)送相關(guān)字段u32_t snd_nxt;?? ??? ??? ??? ?// 下一個(gè)將要發(fā)送的序號(hào)u16_t snd_wnd;?? ??? ??? ??? ?// 當(dāng)前發(fā)送窗口大小u32_t snd_wl1, snd_wl2;?? ??? ?// 上次窗口更新時(shí)收到的數(shù)據(jù)序號(hào)seqno和確認(rèn)號(hào)acknou32_t snd_lbb; ?? ??? ??? ??? ?// 下一個(gè)被緩沖的應(yīng)用程序數(shù)據(jù)的編號(hào)u16_t acked;?? ??? ??? ??? ?// 保存了被確認(rèn)的已發(fā)送長(zhǎng)度u16_t snd_buf; ?? ??? ??? ??? ?// 可用的發(fā)送空間(以字節(jié)為單位)u16_t snd_queuelen;?? ??? ??? ?// 被占用的發(fā)送空間(以數(shù)據(jù)段pbuf為單位)u16_t unsent_oversize;?? ??? ?// 尚未被發(fā)送的字節(jié)數(shù)struct tcp_seg *unsent;?? ??? ?// 未發(fā)送的數(shù)據(jù)段隊(duì)列,鏈表形式struct tcp_seg *unacked;?? ?// 發(fā)送了未收到確認(rèn)的數(shù)據(jù)段隊(duì)列,鏈表形式struct tcp_seg *ooseq;?? ??? ?// 接收到有序序號(hào)以外的數(shù)據(jù)段隊(duì)列,鏈表形式struct pbuf *refused_data;?? ?// 指向上一次成功接收但未被應(yīng)用層取用的數(shù)據(jù)pbuf// 回調(diào)函數(shù)err_t (*sent)(void *arg,struct tcp_pcb *pcb,u16_t space);?? ??? ??? ?// 數(shù)據(jù)成功發(fā)送后被調(diào)用?? ??? ?err_t (*recv)(void *arg,struct tcp_pcb,struct pbuf *p,err_t err);?? ?// 接收到數(shù)據(jù)后被調(diào)用err_t (*connected)(void *arg, struct tcp_pcb *tpcb, err_t err);?? ??? ?// 連接建立后被調(diào)用err_t (*poll)(void *arg, struct tcp_pcb *tpcb);?? ??? ??? ??? ??? ??? ?// 該函數(shù)被內(nèi)核周期性調(diào)用void? (*errf)(void *arg, err_t err);?? ??? ??? ??? ??? ??? ??? ??? ?// 連接發(fā)生錯(cuò)誤時(shí)被調(diào)用// 心跳相關(guān)參數(shù)u32_t keep_idle;?? ??? ??? ?// 最后一個(gè)正常報(bào)文結(jié)束到保活計(jì)時(shí)器(心跳)啟動(dòng)的時(shí)間間隔u32_t keep_intvl;?? ??? ??? ?// 保活計(jì)時(shí)器(心跳)發(fā)送間隔u32_t keep_cnt;?? ??? ??? ??? ?// 保活計(jì)時(shí)器(心跳)最大重發(fā)次數(shù)?? ??u32_t persist_cnt;?? ??? ??? ?// 堅(jiān)持定時(shí)器計(jì)數(shù)值u8_t persist_backoff;?? ??? ?// 堅(jiān)持定時(shí)器開(kāi)關(guān),大于0開(kāi)啟u8_t keep_cnt_sent;?? ??? ??? ?// 保活計(jì)時(shí)器(心跳)最大重發(fā)次數(shù)?? ??}?? ?struct tcp_pcb_listen{IP_PCB;struct tcp_pcb *next;?? ??? ?enum tcp_state state;?? ??? ?u8_t prio;?? ??? ??? ??? ??? ?void *callback_arg;?? ?tcp_accept_fn accept;?? ??? ?u16_t local_port;}注:#define IP_PCB ?? ?ip_addr_t local_ip;?? ??? ?// 本地IPip_addr_t remote_ip;?? ?// 目的IPu8_t ?? ?? so_options;?? ?// 套接字選項(xiàng)?? ?可取值:?? ?#define SOF_ACCEPTCONN??? (u8_t)0x02U#define SOF_REUSEADDR???? (u8_t)0x04U#define SOF_KEEPALIVE???? (u8_t)0x08U#define SOF_BROADCAST???? (u8_t)0x20U#define SOF_LINGER??????? (u8_t)0x80U#define SOF_INHERITED???? (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER)u8_t?? ?? tos;?? ??? ??? ?// 服務(wù)類型u8_t?? ?? ttl;?? ??? ??? ?// TTL這個(gè)TCP控制塊是整個(gè)TCP協(xié)議的核心,TCP協(xié)議實(shí)現(xiàn)的本質(zhì)就是對(duì)TCP控制塊中各字段的操作,所以非常重要!!!******************************************************************************************************************************************************************************************************?? ?tcp_input是TCP層的總輸入函數(shù),它會(huì)為數(shù)據(jù)包尋找一個(gè)匹配的TCP控制塊,以及調(diào)用相應(yīng)的函數(shù)tcp_timewait_input,tcp_listen_input,tcp_process進(jìn)行處理void tcp_input(struct pbuf *p,struct netif *inp){struct tcp_pcb ?? ?*pcb,*prev;struct tcp_pcb_listen *lpcb;u8_t hdrlen;err_t err;// 略過(guò)IP包頭,提取TCP頭iphdr = (struct ip_hdr *)p->payload;tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr)*4)// 移動(dòng)pbuf結(jié)構(gòu)中的數(shù)據(jù)包指針,使指向TCP頭if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))){pbuf_free(p);return;?? ?}// 不處理輸入的廣播包if (ip_addr_isbroadcast(¤t_iphdr_dest, inp) || ip_addr_ismulticast(¤t_iphdr_dest)){pbuf_free(p);return;?? ??? ?}// 驗(yàn)證TCP校驗(yàn)和if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),IP_PROTO_TCP, p->tot_len) != 0){pbuf_free(p);return;?? ?}// 繼續(xù)移動(dòng)pbuf結(jié)構(gòu)中的數(shù)據(jù)包指針,使指向TCP數(shù)據(jù)hdrlen = TCPH_HDRLEN(tcphdr);if(pbuf_header(p, -(hdrlen * 4)){pbuf_free(p);return;?? ?}// 網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)主機(jī)字節(jié)序tcphdr->src = ntohs(tcphdr->src);?? ??? ??? ??? ?// 源端口tcphdr->dest = ntohs(tcphdr->dest);?? ??? ??? ??? ?// 目的端口seqno = tcphdr->seqno = ntohl(tcphdr->seqno);?? ?// 序號(hào)ackno = tcphdr->ackno = ntohl(tcphdr->ackno);?? ?// 確認(rèn)序號(hào)tcphdr->wnd = ntohs(tcphdr->wnd);?? ??? ??? ??? ?// 窗口大小flags = TCPH_FLAGS(tcphdr);?? ??? ??? ??? ??? ??? ?// 6位標(biāo)志位tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0);?? ?// TCP數(shù)據(jù)包中數(shù)據(jù)的總長(zhǎng)度,對(duì)于有FIN或SYN標(biāo)志的數(shù)據(jù)包,該長(zhǎng)度要加1// 以下就是對(duì)接收到的數(shù)據(jù)包進(jìn)行分類處理,也就是尋找合適的接口,根據(jù)IP,port// 首先在tcp_active_pcbs 鏈表池中找,有沒(méi)有匹配的tcp_pcbprev = NULL;for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next){if (pcb->remote_port == tcphdr->src && pcb->local_port == tcphdr->dest && ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) && ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)){// 找到匹配的接口之后,將該tcp_pcb從tcp_active_pcbs鏈表池中取出,然后退出循環(huán)往下運(yùn)行,這時(shí)pcb != NULLif (prev != NULL){prev->next = pcb->next;pcb->next = tcp_active_pcbs;tcp_active_pcbs = pcb;}?? ?break;}?? ?prev = pcb;}// 如果在tcp_active_pcbs中沒(méi)有找到,繼續(xù)在tcp_tw_pcbs 和tcp_listen_pcbs中找if (pcb == NULL){// 在tcp_tw_pcbs中找for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) ?? ?{if (pcb->remote_port == tcphdr->src && pcb->local_port == tcphdr->dest && ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) && ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)){// 進(jìn)入TIME_WAIT狀態(tài)處理(解析見(jiàn)下文),處理完直接這里返回不再往下運(yùn)行tcp_timewait_input(pcb);pbuf_free(p);return;}}// 在tcp_listen_pcbs中找prev = NULL;for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next){// 判斷端口是否匹配if (lpcb->local_port == tcphdr->dest) ?? ?{// 然后判斷IP是否匹配,或者是IPADDR_ANY接收任何IPif (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest) || ip_addr_isany(&(lpcb->local_ip))){// 找到匹配的接口之后退出循環(huán)往下運(yùn)行,這時(shí)lpcb != NULLbreak;}?? ??? ?}prev = (struct tcp_pcb *)lpcb;}// 這里是判斷在tcp_listen_pcbs中是否找到if (lpcb != NULL){// 將該tcp_pcb從tcp_listen_pcbs.listen_pcbs鏈表池中取出if (prev != NULL){((struct tcp_pcb_listen *)prev)->next = lpcb->next;lpcb->next = tcp_listen_pcbs.listen_pcbs;tcp_listen_pcbs.listen_pcbs = lpcb;?? ?}?? ?// 進(jìn)入LISTEN狀態(tài)處理(解析見(jiàn)下文),處理完直接這里返回不再往下運(yùn)行tcp_listen_input(lpcb);pbuf_free(p);return;}}// 如果在tcp_active_pcbs中找到了,則經(jīng)過(guò)處理后進(jìn)入tcp_processif (pcb != NULL){inseg.next = NULL;?? ??? ?// 關(guān)閉報(bào)文段隊(duì)列功能inseg.len = p->tot_len;?? ?// 設(shè)置該報(bào)文段的數(shù)據(jù)長(zhǎng)度inseg.p = p;?? ??? ??? ?// 設(shè)置報(bào)文段數(shù)據(jù)鏈表頭指針inseg.tcphdr = tcphdr;?? ?// 報(bào)文段的TCP頭recv_data = NULL;?? ??? ?// 數(shù)據(jù)接收結(jié)果被保存在該全局變量,然后往上層提交recv_flags = 0;?? ??? ??? ?// tcp_process執(zhí)行完后的結(jié)果(控制塊的狀態(tài)變遷)將會(huì)被保存在該全局變量,首先在這里被清0// tcp_pcb的refused_data指針上是否還記錄有尚未往上層遞交的數(shù)據(jù)if (pcb->refused_data != NULL){// 有的話回調(diào)用戶recv函數(shù)接收未遞交的數(shù)據(jù)TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);// 判斷處理recv函數(shù)的處理結(jié)果,成功refused_data指針清空,繼續(xù)往下執(zhí)行tcp_processif (err == ERR_OK){pcb->refused_data = NULL;} ?? ?// 失敗意味著tcp_pcb都被占用滿,丟棄接收包不再處理,直接返回else if ((err == ERR_ABRT) || (tcplen > 0)){pbuf_free(p);return;}}tcp_input_pcb = pcb;?? ?// 記錄處理當(dāng)前報(bào)文的控制塊// 這里就是進(jìn)入tcp_process處理接收包環(huán)節(jié)了(解析見(jiàn)下文),該函數(shù)實(shí)現(xiàn)了TCP狀態(tài)轉(zhuǎn)換功能err = tcp_process(pcb);// 若返回值為ERR_ABRT,說(shuō)明控制塊已經(jīng)被完全刪除(tcp_abort()),什么也不需要做if (err != ERR_ABRT){// 返回值不為ERR_ABRT時(shí),判斷報(bào)文處理的3種結(jié)果if (recv_flags & TF_RESET) ?? ??? ??? ?// 接收到對(duì)方的復(fù)位報(bào)文{// 回調(diào)用戶的errf函數(shù)TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST);// 刪除控制塊tcp_pcb_remove(&tcp_active_pcbs, pcb);// 釋放控制塊空間memp_free(MEMP_TCP_PCB, pcb);}?? ?else if (recv_flags & TF_CLOSED) ?? ?// 雙方連接成功斷開(kāi){// 刪除控制塊tcp_pcb_remove(&tcp_active_pcbs, pcb);// 釋放控制塊空間memp_free(MEMP_TCP_PCB, pcb);}else{err = ERR_OK;if (pcb->acked > 0) ?? ??? ??? ?// 如果有被確認(rèn)的已發(fā)送數(shù)據(jù)長(zhǎng)度?? ??? ?{// 回調(diào)用戶的send函數(shù)TCP_EVENT_SENT(pcb, pcb->acked, err);if (err == ERR_ABRT){goto aborted;}}if (recv_data != NULL)?? ??? ??? ?// 如果有數(shù)據(jù)被接收到{if (pcb->flags & TF_RXCLOSED) ?? ?// 如果本地TCP控制塊已經(jīng)處于TF_RXCLOSED狀態(tài),則后續(xù)接收到的數(shù)據(jù)都作廢{pbuf_free(recv_data);tcp_abort(pcb);goto aborted;}if (flags & TCP_PSH) ?? ??? ?// 如果TCP標(biāo)志位中帶有PSH{// 設(shè)置pbuf首部的flag字段recv_data->flags |= PBUF_FLAG_PUSH;}// 回調(diào)用戶的recv函數(shù),接收遞交上去的TCP數(shù)據(jù)recv_dataTCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);// 判斷返回值,如果是ERR_ABRT,則丟棄,返回if (err == ERR_ABRT){goto aborted;}// 除此之外,如果返回值是失敗,將這部分尚未往上遞交的數(shù)據(jù)暫存到refused_data指針中if (err != ERR_OK){pcb->refused_data = recv_data;}}if (recv_flags & TF_GOT_FIN)?? ?// 如果收到對(duì)方的FIN請(qǐng)求{// 糾正接收窗口if (pcb->rcv_wnd != TCP_WND){pcb->rcv_wnd++;}// 用一個(gè)NULL指針回調(diào)用戶的recv函數(shù),通過(guò)這種方式用戶程序可以知道對(duì)方的關(guān)閉請(qǐng)求TCP_EVENT_CLOSED(pcb, err);if (err == ERR_ABRT){goto aborted;}}tcp_input_pcb = NULL;?? ??? ?// 當(dāng)前報(bào)文到此處理完畢,清空當(dāng)前報(bào)文的控制塊tcp_output(pcb);?? ??? ??? ?// 輸出報(bào)文}}aborted:tcp_input_pcb = NULL;recv_data = NULL;if (inseg.p != NULL){pbuf_free(inseg.p);inseg.p = NULL;}}else{// 如果在3張鏈表里都未找到匹配的pcb,則調(diào)用tcp_rst向源主機(jī)發(fā)送一個(gè)TCP復(fù)位數(shù)據(jù)包if (!(TCPH_FLAGS(tcphdr) & TCP_RST)){tcp_rst(ackno, seqno + tcplen,ip_current_dest_addr(), ip_current_src_addr(),tcphdr->dest, tcphdr->src);}pbuf_free(p);}}******************************************************************************************************************************************************************************************************?? ?// 本函數(shù)是處于LISTEN狀態(tài)的控制塊對(duì)輸入報(bào)文的處理函數(shù),處于LISTEN狀態(tài)的控制塊只能響應(yīng)SYN握手包err_t tcp_listen_input(struct tcp_pcb_listen *pcb){struct tcp_pcb *npcb;err_t rc;// 處于listen狀態(tài)的pcb只能響應(yīng)SYN握手包,對(duì)含有ACK標(biāo)志的輸入報(bào)文返回一個(gè)RST報(bào)文if (flags & TCP_ACK){tcp_rst(ackno + 1, seqno + tcplen,ip_current_dest_addr(), ip_current_src_addr(),tcphdr->dest, tcphdr->src);}// 處于listen狀態(tài)的服務(wù)器端等到了SYN握手包else if (flags & TCP_SYN){// 建立一個(gè)新的tcp_pcb,因?yàn)樘幱趖cp_listen_pcbs鏈表上的pcb是tcp_pcb_listen結(jié)構(gòu)的,而其他鏈表上的pcb是tcp_pcb結(jié)構(gòu)npcb = tcp_alloc(pcb->prio);?? ?// 如果新建失敗,往往是因?yàn)閮?nèi)存不夠if (npcb == NULL){TCP_STATS_INC(tcp.memerr);ERR_MEM;}// 為這個(gè)新建的tcp_pcb填充成員ip_addr_copy(npcb->local_ip, current_iphdr_dest);npcb->local_port = pcb->local_port;ip_addr_copy(npcb->remote_ip, current_iphdr_src);npcb->remote_port = tcphdr->src;npcb->state = SYN_RCVD;?? ??? ??? ??? ??? ??? ??? ??? ?// 進(jìn)入SYN_RCVD狀態(tài)npcb->rcv_nxt = seqno + 1;?? ??? ??? ??? ??? ??? ??? ?// 期望接收到的下一個(gè)序號(hào),注意加1npcb->rcv_ann_right_edge = npcb->rcv_nxt;?? ??? ??? ?// 初始化右側(cè)通告窗口npcb->snd_wnd = tcphdr->wnd;?? ??? ??? ??? ??? ??? ?// 根據(jù)TCP頭中對(duì)方可接收數(shù)據(jù)長(zhǎng)度,初始化本地發(fā)送窗口大小npcb->ssthresh = npcb->snd_wnd;?? ??? ??? ??? ??? ??? ?// 擁塞算法相關(guān),暫略npcb->snd_wl1 = seqno - 1;?? ??? ??? ??? ??? ??? ??? ?// 初始化上次窗口更新時(shí)收到的序號(hào)npcb->callback_arg = pcb->callback_arg;?? ??? ??? ??? ?// 初始化用戶自定義數(shù)據(jù)npcb->accept = pcb->accept;?? ??? ??? ??? ??? ??? ??? ?// 初始化連接accept時(shí)的回調(diào)函數(shù)?? ?npcb->so_options = pcb->so_options & SOF_INHERITED;?? ?// 繼承socket選項(xiàng)TCP_REG(&tcp_active_pcbs, npcb);?? ??? ??? ??? ??? ?// 將這個(gè)設(shè)置好的tcp_pcb注冊(cè)到tcp_active_pcbs鏈表中去tcp_parseopt(npcb);?? ??? ??? ??? ??? ??? ??? ??? ??? ?// 從收到的SYN握手包中提取TCP頭中選項(xiàng)字段的值,并設(shè)置到自己的tcp_pcbnpcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip));?? ?// 初始化mss// 回復(fù)帶有SYN和ACK標(biāo)志的握手?jǐn)?shù)據(jù)包rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK);if (rc != ERR_OK){tcp_abandon(npcb, 0);return rc;}// TCP層的總輸出函數(shù),詳見(jiàn)下文return tcp_output(npcb);}return ERR_OK;}******************************************************************************************************************************************************************************************************// 本函數(shù)是處于TIMEWAIT狀態(tài)的控制塊處理輸入報(bào)文的函數(shù)err_t tcp_timewait_input(struct tcp_pcb *pcb){// 如果報(bào)文中含RST標(biāo)志,直接丟棄if (flags & TCP_RST) ?{return ERR_OK;?? ?}?? ?// 如果報(bào)文中含SYN標(biāo)志if (flags & TCP_SYN){// 如果SYN的序號(hào)在接收窗口內(nèi),返回一個(gè)RST報(bào)文if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)){tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),tcphdr->dest, tcphdr->src);return ERR_OK;?? ?}}// 如果報(bào)文中含F(xiàn)IN標(biāo)志else if(flags & TCP_FIN){pcb->tmr = tcp_ticks;}// 如果TCP報(bào)文中有數(shù)據(jù)if(tcp_len > 0){pcb->flags |= TF_ACK_NOW;?? ?// 將當(dāng)前控制塊設(shè)為TF_ACK_NOW狀態(tài)// TCP層的總輸出函數(shù),詳見(jiàn)下文return tcp_output(pcb);?? ??? ?}return ERR_OK;}******************************************************************************************************************************************************************************************************?? ?// 除了處于LISTEN、TIME_WAIT狀態(tài)的其余所有狀態(tài)的pcb控制塊,其報(bào)文的輸入處理都在這里,該函數(shù)主要實(shí)現(xiàn)了TCP狀態(tài)轉(zhuǎn)換功能err_t tcp_process(struct tcp_pcb *pcb){struct ?? ?tcp_seg *rseg;u8_t?? ?acceptable = 0;err_t?? ?err;err?? ?= ERR_OK;// 首先判斷該報(bào)文是不是一個(gè)RST報(bào)文if(flags & TCP_RST){// 判斷該RST報(bào)文是否合法if (pcb->state == SYN_SENT) ?? ?// 第一種情況,連接處于SYN_SENT狀態(tài){if (ackno == pcb->snd_nxt) ?? ?// 且輸入報(bào)文中的確認(rèn)號(hào)就是控制塊中想要發(fā)送的下一個(gè)序號(hào){acceptable = 1;?? ?}}else?? ??? ??? ??? ??? ??? ??? ?// 第二種情況,其他狀態(tài)下,輸入報(bào)文中的序號(hào)在接收窗口內(nèi){if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,pcb->rcv_nxt+pcb->rcv_wnd)){acceptable = 1;}?? ?}// 如果RST報(bào)文合法,則需要復(fù)位當(dāng)前連接的控制塊,非法則直接返回不做處理if (acceptable){recv_flags |= TF_RESET;?? ??? ??? ?// 表明該輸入報(bào)文的處理結(jié)果中包含TF_RESETpcb->flags &= ~TF_ACK_DELAY;?? ?// 因?yàn)檩斎胧荝ST報(bào)文,意味當(dāng)前控制塊必然不處于TF_ACK_DELAY狀態(tài)return ERR_RST;?? ?}else{return ERR_OK;}}// 然后處理握手報(bào)文SYN,在連接已經(jīng)建立情況下,但還是接收到對(duì)方的握手包,說(shuō)明這可能是一個(gè)超時(shí)重發(fā)的握手包,直接向?qū)Ψ椒祷匾粋€(gè)ACK即可if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)){tcp_ack_now(pcb);?? ??? ??? ??? ??? ?// #define tcp_ack_now(pcb) ?? ?pcb->flags |= TF_ACK_NOW?? ?- 將當(dāng)前控制塊設(shè)為TF_ACK_NOW狀態(tài)return ERR_OK;?? ?}// TCP連接不處于半關(guān)閉前提下,更新控制塊的活動(dòng)計(jì)數(shù)器if ((pcb->flags & TF_RXCLOSED) == 0){pcb->tmr = tcp_ticks;}// 保活報(bào)文計(jì)數(shù)器清0pcb->keep_cnt_sent = 0;// 處理報(bào)文首部中的選項(xiàng)字段(暫略)tcp_parseopt(pcb);// 根據(jù)當(dāng)前所處的不同的TCP狀態(tài)執(zhí)行相應(yīng)動(dòng)作switch (pcb->state){case SYN_SENT:?? ?// 客戶端發(fā)出SYN后,就處于該狀態(tài)等待服務(wù)器返回SYN+ACK// 如果收到的是SYN+ACK,且輸入報(bào)文中的確認(rèn)號(hào),就是控制塊中已發(fā)送,但尚未收到應(yīng)答報(bào)文段中的序號(hào)+1if ((flags & TCP_ACK) && (flags & TCP_SYN) && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1){pcb->snd_buf++;?? ??? ??? ??? ??? ??? ??? ?// 發(fā)出SYN被返回的ACK確認(rèn),釋放1字節(jié)空間,所以可用的發(fā)送空間加1字節(jié)?? ?pcb->rcv_nxt = seqno + 1;?? ??? ??? ??? ?// 期望接收的下一個(gè)序號(hào),即接收端向發(fā)送端ACK報(bào)文中的確認(rèn)號(hào)pcb->rcv_ann_right_edge = pcb->rcv_nxt;?? ?// 初始化通告窗口的右邊界值(略存疑問(wèn))pcb->lastack = ackno;?? ??? ??? ??? ??? ?// 更新接收到的最大確認(rèn)號(hào)字段,也就是更新上一個(gè)確認(rèn)號(hào)字段pcb->snd_wnd = tcphdr->wnd;?? ??? ??? ??? ?// 發(fā)送窗口設(shè)置為接收窗口大小,實(shí)現(xiàn)流量控制pcb->snd_wl1 = seqno - 1; ?? ??? ??? ??? ?// 上次窗口更新時(shí)收到的數(shù)據(jù)序號(hào)pcb->state = ESTABLISHED;?? ??? ??? ??? ?// 進(jìn)入ESTABLISHED狀態(tài)pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));?? ?// 計(jì)算并設(shè)置最大報(bào)文段pcb->ssthresh = pcb->mss * 10;?? ??? ??? ??? ??? ??? ??? ??? ?// 重設(shè)mss后,ssthresh值也要相應(yīng)修改pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);?? ?// 初始化阻塞窗口--pcb->snd_queuelen;?? ??? ??? ?// SYN被返回的ACK確認(rèn),所以占用的pbuf個(gè)數(shù)減1?? ?rseg = pcb->unacked;?? ??? ??? ?// 從發(fā)送了未收到確認(rèn)的數(shù)據(jù)段隊(duì)列中取出SYN報(bào)文,相當(dāng)于刪除pcb->unacked = rseg->next;?? ??? ?// 指向下一個(gè)發(fā)送了未收到確認(rèn)的數(shù)據(jù)段if(pcb->unacked == NULL)?? ??? ?// 如果未確認(rèn)的數(shù)據(jù)段為空,則停止重傳定時(shí)器pcb->rtime = -1;else ?? ??? ??? ??? ??? ??? ??? ?// 如果隊(duì)列中還有報(bào)文,則復(fù)位重傳定時(shí)器和重傳次數(shù){pcb->rtime = 0;pcb->nrtx = 0;}tcp_seg_free(rseg);?? ??? ??? ??? ?// 釋放取下的SYN報(bào)文段內(nèi)存空間TCP_EVENT_CONNECTED(pcb, ERR_OK, err);?? ?// 回調(diào)用戶的connect函數(shù)(詳解見(jiàn)下文)if (err == ERR_ABRT){return ERR_ABRT;}tcp_ack_now(pcb);?? ??? ??? ??? ?// 向服務(wù)器返回ACK,三次握手結(jié)束,具體含義見(jiàn)L753}// 如果只收到對(duì)方的ACK卻沒(méi)有SYN,則向?qū)Ψ椒祷豏ST報(bào)文else if(flag & TCP_ACK){tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),tcphdr->dest, tcphdr->src);}break;case SYN_RCVD:?? ?// 服務(wù)器發(fā)送SYN+ACK后,就處于該狀態(tài),等待客戶端返回ACK// 如果收到ACK,也就是三次握手的最后一個(gè)報(bào)文if(flags & TCP_ACK){// 如果ACK合法if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){u16_t old_cwnd;pcb->state = ESTABLISHED;?? ?// 進(jìn)入ESTABLISHED狀態(tài)TCP_EVENT_ACCEPT(pcb, ERR_OK, err);?? ??? ?// 回調(diào)用戶的accept函數(shù)if (err != ERR_OK) ?? ??? ??? ??? ??? ??? ?// 如果accept函數(shù)返回錯(cuò)誤,則關(guān)閉當(dāng)前連接{if (err != ERR_ABRT){tcp_abort(pcb);}return ERR_ABRT;}old_cwnd = pcb->cwnd;?? ??? ?// 保存舊的阻塞窗口tcp_receive(pcb);?? ??? ??? ?// 如果該ACK報(bào)文中還攜帶了數(shù)據(jù),則調(diào)用tcp_receive處理報(bào)文中的數(shù)據(jù)(解析見(jiàn)下文)// 調(diào)整本地未被確認(rèn)的字節(jié)數(shù),因?yàn)镾YN報(bào)文占用1個(gè)字節(jié),所以減1if (pcb->acked != 0) ?? ??? ?{pcb->acked--;?? ??? ??? ??? ?}pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);?? ?// 初始化阻塞窗口// 如果在上面的tcp_receive處理結(jié)果中包含F(xiàn)IN標(biāo)志if (recv_flags & TF_GOT_FIN){tcp_ack_now(pcb);?? ??? ??? ?// 回復(fù)ACK,響應(yīng)對(duì)方的FIN握手標(biāo)志pcb->state = CLOSE_WAIT;?? ?// 進(jìn)入CLOSE_WAIT狀態(tài)}}}else{// 對(duì)于不合法的ACK,則返回一個(gè)RSTtcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),tcphdr->dest, tcphdr->src);}?? ?}// 如果收到客戶端重復(fù)SYN握手包,說(shuō)明SYN+ACK包丟失,需要重傳else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)){tcp_rexmit(pcb);}break;case CLOSE_WAIT:?? ?// 服務(wù)器處于接收關(guān)閉的半連接狀態(tài),會(huì)一直等待上層應(yīng)用執(zhí)行關(guān)閉指令,發(fā)出FIN,并將狀態(tài)變?yōu)長(zhǎng)ASK_ACKcase ESTABLISHED:?? ?// 連接雙方都處于穩(wěn)定狀態(tài)tcp_receive(pcb);?? ??? ??? ??? ?// 調(diào)用函數(shù)處理報(bào)文中的數(shù)據(jù)// 如果在上面的tcp_receive處理結(jié)果中包含F(xiàn)IN標(biāo)志if (recv_flags & TF_GOT_FIN){tcp_ack_now(pcb);?? ??? ??? ?// 回復(fù)ACK,響應(yīng)對(duì)方的FIN握手標(biāo)志pcb->state = CLOSE_WAIT;?? ?// 進(jìn)入CLOSE_WAIT狀態(tài)}break;case FIN_WAIT_1:?? ?// 上層應(yīng)用主動(dòng)執(zhí)行關(guān)閉指令,發(fā)送FIN后處于該狀態(tài)(通常對(duì)于客戶端來(lái)講)tcp_receive(pcb);?? ??? ??? ??? ??? ??? ?// 調(diào)用函數(shù)處理報(bào)文中的數(shù)據(jù)// 如果在上面的tcp_receive處理結(jié)果中包含F(xiàn)IN標(biāo)志if (recv_flags & TF_GOT_FIN){// 如果該報(bào)文同時(shí)包含一個(gè)合法ACK,意味著本地端將直接跳過(guò)FIN_WAIT_2進(jìn)入TIME_WAIT狀態(tài)if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)){tcp_ack_now(pcb);?? ??? ??? ??? ?// 回復(fù)ACKtcp_pcb_purge(pcb);?? ??? ??? ??? ?// 清除該連接中的所有現(xiàn)存數(shù)據(jù)TCP_RMV(&tcp_active_pcbs, pcb);?? ?// 從tcp_active_pcbs鏈表中刪除該控制塊pcb->state = TIME_WAIT;?? ??? ??? ?// 跳過(guò)FIN_WAIT_2狀態(tài),直接進(jìn)入TIME_WAIT狀態(tài)TCP_REG(&tcp_tw_pcbs, pcb);?? ??? ?// 將該控制塊加入tcp_tw_pcbs鏈表?? ?}// 如果該報(bào)文不含ACK,即表示雙方同時(shí)執(zhí)行了關(guān)閉連接操作else{tcp_ack_now(pcb);?? ??? ??? ??? ?// 返回ACKpcb->state = CLOSING;?? ??? ??? ?// 進(jìn)入CLOSING狀態(tài)}}// 如果只收到有效的ACKelse if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)){pcb->state = FIN_WAIT_2;?? ??? ??? ?// 進(jìn)入FIN_WAIT_2狀態(tài)}break;?? ?case FIN_WAIT_2:?? ?// 主動(dòng)關(guān)閉,發(fā)送FIN握手且收到ACK后處于該狀態(tài)?? ??? ?tcp_receive(pcb);?? ??? ??? ??? ??? ??? ?// 調(diào)用函數(shù)處理報(bào)文中的數(shù)據(jù)// 如果在上面的tcp_receive處理結(jié)果中包含F(xiàn)IN標(biāo)志if (recv_flags & TF_GOT_FIN){tcp_ack_now(pcb);?? ??? ??? ??? ??? ?// 回復(fù)ACKtcp_pcb_purge(pcb);?? ??? ??? ??? ??? ?// 清除該連接中的所有現(xiàn)存數(shù)據(jù)TCP_RMV(&tcp_active_pcbs, pcb);?? ??? ?// 從tcp_active_pcbs鏈表中刪除該控制塊pcb->state = TIME_WAIT;?? ??? ??? ??? ?// 進(jìn)入TIME_WAIT狀態(tài)TCP_REG(&tcp_tw_pcbs, pcb);?? ??? ??? ?// 將該控制塊加入tcp_tw_pcbs鏈表}break;case CLOSING:?? ??? ?// 雙方同時(shí)執(zhí)行主動(dòng)關(guān)閉,處于該狀態(tài)(特殊情況)tcp_receive(pcb);?? ??? ??? ??? ??? ??? ?// 調(diào)用函數(shù)處理報(bào)文中的數(shù)據(jù)// 如果收到合法ACKif (flags & TCP_ACK && ackno == pcb->snd_nxt){tcp_pcb_purge(pcb);?? ??? ??? ??? ??? ?// 清除該連接中的所有現(xiàn)存數(shù)據(jù)TCP_RMV(&tcp_active_pcbs, pcb);?? ??? ?// 從tcp_active_pcbs鏈表中刪除該控制塊pcb->state = TIME_WAIT;?? ??? ??? ??? ?// 進(jìn)入TIME_WAIT狀態(tài)TCP_REG(&tcp_tw_pcbs, pcb);?? ??? ??? ?// 將該控制塊加入tcp_tw_pcbs鏈表}break;case LAST_ACK:?? ??? ?// 服務(wù)器在執(zhí)行被動(dòng)關(guān)閉時(shí),發(fā)送完FIN,等待ACK時(shí)處于該狀態(tài)tcp_receive(pcb);?? ??? ??? ??? ??? ??? ?// 調(diào)用函數(shù)處理報(bào)文中的數(shù)據(jù)// 如果收到合法ACKif (flags & TCP_ACK && ackno == pcb->snd_nxt){recv_flags |= TF_CLOSED;?? ??? ??? ?// recv_flags設(shè)置為TF_CLOSED,由tcp_input函數(shù)對(duì)該控制塊進(jìn)行釋放和清除}break;default:break;}return ERR_OK;}******************************************************************************************************************************************************************************************************
總結(jié)
以上是生活随笔為你收集整理的lwip之数据收发流程_2的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: lwip之数据收发流程_1
- 下一篇: #if 和#ifdef的区别