/* Let the stack know that we have taken the data. */
msg.function = do_recv;
msg.msg.conn = conn;
if (buf != NULL) {
msg.msg.msg.r.len = buf->p->tot_len;
} else {
msg.msg.msg.r.len = 1;
}
TCPIP_APIMSG(&msg);
/* If the change in the right edge of window is significant (default
* watermark is TCP_WND/2), then send an explicit update now.
* Otherwise wait for a packet to be sent in the normal course of
* events (or more window to be available later) */
if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD)
tcp_ack_now(pcb);
到这里终于知道了,原来TCPWEINDOW在这里更新啊。不错不错。什么时候更新呢?那是有条件的
这就是条件。
于是解决了第一个疑惑那就WIN的UPDATA.
接下来就是WIN=0?为何?
其实上个问题已经解释清楚了,我们只需要引深一下就好,那就是WIN只有在应用程序读走TCP推上来的BUF后才会更新WIN,否则的话就会对WIN进行相应载荷的减操作。如果应用程序很忙,你叫他他并不响应,此时WIN就处于不断下滑不断减少的境地。然后WIN=0,最终用完了WIN,因为应用程序很忙嘛,他没有时间了作别的他得处理,至于为什么忙,比如一个更改优先级的线程就绪了执行中而读取他的线程挂起等待,这就是典型的。很多原因的。于是WIN=0了。HOST一看WIN=0,就想:我擦:竟然没有空间了?好吧我停止吧。你没地方让我的人过去呆在那里?于是乎他等了一会就挂断聊!一个RST随之产生OK,这样似乎很符合抓包获取的流程。事实应该89不离十。这里面还有TCP的另一个概念,就是延时的概念,也就是PUSH和ACK并存的时候,在TCP数据发送的时候TCP并不是立即发送而是有规律的推迟发送,以利用一个包传送更多的信息,这是另一个重要的模块。不过这里不讨论此方面的问题。
再回到最初的地方,如果按照以上所述则则应用层处理的越快UPDATA应该每次都很顺利的更新。试试看
send(tcp_clint_sock, recv_data,bytes_received, 0);
去掉邮箱之后的此函数之后,再去开wireshak 抓取的包就是一个完美的情形,也就是预期的结果。tcp流一直持续,并没有断过了,这印证了之前的推论和实际情况之间是等价的。也就是说应用层只有尽快的处理完数据才可以流畅。这样一个TCP流控就展现在面前:
今天和某君讨论HTTP的问题,由于某君是裸奔的所以它不存在邮箱的问题。这样就有点麻烦了,得使用底层丢上来的BUF,结果他又忘记了在APP程序中是free掉内存,最终WEB刷新几下就死翘翘聊。如果这里采用邮箱就不会出现内存泄露这样的情况,如下:
/* copy the contents of the received buffer into
the supplied memory pointer mem */
netbuf_copy_partial(buf, (u8_t*)mem + off, copylen, sock->lastoffset);
系统会自动的吧BUF释放掉并把数据COPY到应用层里面,这样就实现了绝对的分层!这才是绝对的分层。否则就是伪分层的。应用层还是脱离不开底层的。这也是覆盖OS和不覆盖OS的区别之一吧。
但是使用OS时有代价的,要牺牲更多的内存和时间性。比无OS系统响应时间更慢,这是一定的。也是看应用而选择的特殊考量。