recv_data = NULL;
recv_flags = 0;
開始構(gòu)建TCP段準(zhǔn)備交付上層的結(jié)構(gòu)準(zhǔn)備工作。可見這個(gè)結(jié)構(gòu)繼承PBUF
緊接著執(zhí)行tcp_process(struct tcp_pcb *pcb)
開始處理TCP事務(wù),其實(shí)是主要處理TCP的那狀態(tài)圖,根據(jù)
enum tcp_state {
CLOSED = 0,
LISTEN = 1,
SYN_SENT = 2,
SYN_RCVD = 3,
ESTABLISHED = 4,
FIN_WAIT_1 = 5,
FIN_WAIT_2 = 6,
CLOSE_WAIT = 7,
CLOSING = 8,
LAST_ACK = 9,
TIME_WAIT = 10
};
這個(gè)狀態(tài)處理各個(gè)分支的枝枝叉叉。最后鎖定這個(gè)函數(shù)
tcp_receive(struct tcp_pcb *pcb)
這個(gè)函數(shù)開始處理我兩件事3,一件事是TCP的ACK一件事是含有數(shù)據(jù)包的TCP報(bào)文。把它交給上層。但是他是如何交上去的,還得猜
if (flags & TCP_ACK) 這個(gè)就是處理TCP的ACK包,我們忽略這不是重點(diǎn),因?yàn)槲蚁肟纯吹讓訑?shù)據(jù)如何向上的。向下?lián)Q個(gè)選項(xiàng)
/* If the incoming segment contains data, we must process it
further. */
if (tcplen > 0) {。。。}
按照解釋上說的是只做三件事:
/* This code basically does three things:
+) If the incoming segment contains data that is the next
in-sequence data, this data is passed to the application. This
might involve trimming the first edge of the data. The rcv_nxt
variable and the advertised window are adjusted.
+) If the incoming segment has data that is above the next
sequence number expected (->rcv_nxt), the segment is placed on
the ->ooseq queue. This is done by finding the appropriate
place in the ->ooseq queue (which is ordered by sequence
number) and trim the segment in both ends if needed. An
immediate ACK is sent to indicate that we received an
out-of-sequence segment.
+) Finally, we check if the first segment on the ->ooseq queue
now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If
rcv_nxt > ooseq->seqno, we must trim the first edge of the
segment on ->ooseq before we adjust rcv_nxt. The data in the
segments that are now on sequence are chained onto the
incoming segment so that we only need to call the application
once.
*/
終于出來OOS對列了,這個(gè)稱之為:out-of-sequence 隊(duì)列。如上文所述
這個(gè)OOS是用來存儲失序的SEQ號所排的隊(duì),并且按照序號鏈接起來一并交付應(yīng)用層處理,這種失序在局域網(wǎng)中小數(shù)據(jù)根本沒有。只有
在廣域網(wǎng)中或或者在局域網(wǎng)高速數(shù)據(jù)吞吐的情況下才會發(fā)生,尤其是廣域網(wǎng)中這種情況完全可能,
TCP的失序問題是這樣產(chǎn)生的
HOST端發(fā)送的數(shù)據(jù)經(jīng)過若干道路由,有可能有的去天津饒了一圈,有的去海南轉(zhuǎn)了圈,再回來肯定有時(shí)間差,時(shí)間差很可能會發(fā)生序號小的后到達(dá),而序號大的先到達(dá),這是完全有可能的,這是OOS隊(duì)列起作用了,他會緩存住失序的TCP段,并發(fā)出失序應(yīng)答。然后重新連接PBUF把序號鏈接的BUF連接重新分配后一并交付應(yīng)用層。
1、對載荷進(jìn)行填充,填充目標(biāo)地址。校驗(yàn)等
2、SndState = STATE_M_TX_XMIT;激活發(fā)送,打開發(fā)送接口驅(qū)動PortEnable( FALSE, TRUE );
3、發(fā)送 /* check if we are finished. */
if( SndBufferCount != 0 )
{
PortPutByte( ( CHAR )*pucMasterSndBufferCur );
pucMasterSndBufferCur++; /* next byte in sendbuffer. */
SndBufferCount--;
}
4、發(fā)送完畢,開始判斷當(dāng)前是否廣播然后區(qū)別對待(打開接受關(guān)閉發(fā)送,打開接收就是要接受回應(yīng)的。)
/* If the frame is broadcast ,master will enable timer of convert delay,
* else master will enable timer of respond timeout. */
if ( xFrameIsBroadcast == TRUE )
{
vMBMasterPortTimersConvertDelayEnable( );
}
else
{
vMBMasterPortTimersRespondTimeoutEnable( );
}
兩種情況都是開啟定時(shí)器計(jì)時(shí)開始,但是時(shí)間長短不一樣而已。
5、關(guān)閉POLL。
6、開始等待延時(shí)結(jié)束
7、延時(shí)完成回調(diào)函數(shù)激活
/* A frame was send finish and convert delay or respond timeout expired.
* If the frame is broadcast,The master will idle,and if the frame is not
* broadcast.Notify the listener process error.*/
向應(yīng)用程序報(bào)告當(dāng)前的情況,是廣播的話就是當(dāng)前延時(shí)結(jié)束,是發(fā)送的話就是沒有回應(yīng)應(yīng)該報(bào)錯(cuò)誤。這樣一個(gè)超時(shí)錯(cuò)誤響應(yīng)的就產(chǎn)生了
于是通過一個(gè)隊(duì)列接口通知應(yīng)用即可】】
PortEventPost(EV_MASTER_ERROR_PROCESS);
8、 關(guān)閉定時(shí)器,發(fā)送狀態(tài)重新回到 eSndState = STATE_M_TX_IDLE;