recv_data = NULL;
recv_flags = 0;
開始構建TCP段準備交付上層的結構準備工作。可見這個結構繼承PBUF
緊接著執行tcp_process(struct tcp_pcb *pcb)
開始處理TCP事務,其實是主要處理TCP的那狀態圖,根據
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
};
這個狀態處理各個分支的枝枝叉叉。最后鎖定這個函數
tcp_receive(struct tcp_pcb *pcb)
這個函數開始處理我兩件事3,一件事是TCP的ACK一件事是含有數據包的TCP報文。把它交給上層。但是他是如何交上去的,還得猜
if (flags & TCP_ACK) 這個就是處理TCP的ACK包,我們忽略這不是重點,因為我想看看底層數據如何向上的。向下換個選項
/* 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對列了,這個稱之為:out-of-sequence 隊列。如上文所述
這個OOS是用來存儲失序的SEQ號所排的隊,并且按照序號鏈接起來一并交付應用層處理,這種失序在局域網中小數據根本沒有。只有
在廣域網中或或者在局域網高速數據吞吐的情況下才會發生,尤其是廣域網中這種情況完全可能,
TCP的失序問題是這樣產生的
HOST端發送的數據經過若干道路由,有可能有的去天津饒了一圈,有的去海南轉了圈,再回來肯定有時間差,時間差很可能會發生序號小的后到達,而序號大的先到達,這是完全有可能的,這是OOS隊列起作用了,他會緩存住失序的TCP段,并發出失序應答。然后重新連接PBUF把序號鏈接的BUF連接重新分配后一并交付應用層。
1、對載荷進行填充,填充目標地址。校驗等
2、SndState = STATE_M_TX_XMIT;激活發送,打開發送接口驅動PortEnable( FALSE, TRUE );
3、發送 /* check if we are finished. */
if( SndBufferCount != 0 )
{
PortPutByte( ( CHAR )*pucMasterSndBufferCur );
pucMasterSndBufferCur++; /* next byte in sendbuffer. */
SndBufferCount--;
}
4、發送完畢,開始判斷當前是否廣播然后區別對待(打開接受關閉發送,打開接收就是要接受回應的。)
/* 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( );
}
兩種情況都是開啟定時器計時開始,但是時間長短不一樣而已。
5、關閉POLL。
6、開始等待延時結束
7、延時完成回調函數激活
/* 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.*/
向應用程序報告當前的情況,是廣播的話就是當前延時結束,是發送的話就是沒有回應應該報錯誤。這樣一個超時錯誤響應的就產生了
于是通過一個隊列接口通知應用即可】】
PortEventPost(EV_MASTER_ERROR_PROCESS);
8、 關閉定時器,發送狀態重新回到 eSndState = STATE_M_TX_IDLE;