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;