lwiptcp接收处理函数.docx
- 文档编号:859601
- 上传时间:2022-10-13
- 格式:DOCX
- 页数:11
- 大小:24.63KB
lwiptcp接收处理函数.docx
《lwiptcp接收处理函数.docx》由会员分享,可在线阅读,更多相关《lwiptcp接收处理函数.docx(11页珍藏版)》请在冰豆网上搜索。
lwiptcp接收处理函数
竭诚为您提供优质文档/双击可除
lwiptcp接收处理函数
篇一:
LwIp之三Tcp层发送相关
LwIp之Tcp层发送相关
20XX-05-1600:
42:
09
标签:
原创作品,允许转载,转载时请务必以超链接形式标明文章原始出处、作者信息和本声明。
否则将追究法律责任。
20XX-5-11LwIp之Tcp层发送相关
现在我们正式开始进入对Tcp的研究,它属于传输层协议,它为应用程序提供了可靠的字节流服务。
在LwIp中基本的Tcp处理过程被分割为六个功能函数的实现:
tcp_input(),tcp_process(),tcp_receive()【与Tcp输入有关】,tcp_write(),tcp_enqueue(),tcp_output()【用于Tcp输出】。
这些是从大的方面来划分的。
现在先从小部tcp.c文件来分析一下:
我们知道这里的函数都是被socket那一层的最终调用的。
为了利于分析,我选择lwip_send函数来分析,具体不多说,最终调用到了
staticerr_tdo_writemore(structnetconn*conn)这个函数,当然这期间也做了不少工作,最主要的就是把发送数据的指针放到了msg的指定变量中
msg.msg.msg.w.dataptr=dataptr;//指针
msg.msg.msg.w.len=size;//长度
这些又经过转化放到了netconn的write_msg中
最后就是对do_writemore的调用了,下面详细分析这个函数。
这个函数的最直接调用有以下几个:
available=tcp_sndbuf(conn->pcb.tcp);
err=tcp_write(conn->pcb.tcp,dataptr,len,conn->write_msg->msg.w.apiflags);err=tcp_output_nagle(conn->pcb.tcp);
err=tcp_output(conn->pcb.tcp);
好,先看tcp_sndbuf这个。
从其参数,我们应该想像pcb的重要性。
#definetcp_sndbuf(pcb)((pcb)->snd_buf)//由下面分析得这里直接返回buf大小那就继续跟踪这个pcb好了。
是的,这还得从lwip_socket开始,在创建连接netconn的时候调用了do_newconn,它接着调用了pcb_new,在这个函数中如果是tcp的话有以下代码
msg->conn->pcb.tcp=tcp_new();
哈哈,还记得吧,在前面我讨论到了这里,就没有再讨论了。
嗯,现在开始吧。
*createsanewTcpprotocolcontrolblockbutdoesntplaceiton
*anyoftheTcppcblists.
*Thepcbisnotputonanylistuntilbindingusingtcp_bind().
structtcp_pcb*tcp_new(void)
{
returntcp_alloc(Tcp_pRIo_noRmAL);
}
也许注释的意义更大一些吧,哈哈,至此,我们从注释可以知道,tcp_bind的作用是把tcp的pcb放入list中,至少是某一个list
×××××××××××××××××××××××××××××××××××××××既然都提到了,似乎不说说有点过意不去啊。
Lwid_bind函数最终会调用到tcp_bind【当然是tcp为例进行分析】。
这个函数也比较有意思,在进入正题之前先来了下面这么个调用
if(port==0)
{
port=tcp_new_port();
}
意思很明显,就是分配个新的端口号,有意思的就是这个端口号的分配函数tcp_new_portstaticu16_t
tcp_new_port(void)
{
structtcp_pcb*pcb;
#ifndefTcp_LocAL_poRT_RAnge_sTART
#defineTcp_LocAL_poRT_RAnge_sTART4096
#defineTcp_LocAL_poRT_RAnge_enD0x7fff
#endif
staticu16_tport=Tcp_LocAL_poRT_RAnge_sTART;
again:
if(++port>Tcp_LocAL_poRT_RAnge_enD){
port=Tcp_LocAL_poRT_RAnge_sTART;
}
for(pcb=tcp_active_pcbs;pcb!
=nuLL;pcb=pcb->next){
if(pcb->local_port==port){
gotoagain;
}
}
for(pcb=tcp_tw_pcbs;pcb!
=nuLL;pcb=pcb->next){
if(pcb->local_port==port){
gotoagain;
}
}
for(pcb=(structtcp_pcb*)tcp_listen_pcbs.pcbs;pcb!
=nuLL;pcb=pcb->next){if(pcb->local_port==port){
gotoagain;
}
}
returnport;
}分别检查了3个pcb链表,本来我不想把这个函数的实现列在这里的,但是这里告诉了我们一些东西,至少我们知道有3个pcb的链表,分别是tcp_active_pcbs【处于接受发送数据状态的pcbs】、tcp_tw_pcbs【处于时间等待状态的pcbs】、tcp_listen_pcbs【处于监听状态的pcbs】。
似乎tcp_bind函数更有意思,它分别检查了4个pcbs链表,除了上面的三个还有一个tcp_bound_pcbs
【处于已经绑定但还没有连接或者监听pcbs】。
作用是是否有与目前pcb的ipaddr相同的pcb存在。
不过这些都不是最重要的,Tcp_Reg(才是我们的目的,果然如此,直接加入到了tcp_bound_pcbs链表中了。
×××××××××××××××××××××××××××××××××××××××structtcp_pcb*tcp_alloc(u8_tprio)//是的,你没看错,这个参数是学名是叫优先级{
pcb=memp_malloc(memp_Tcp_pcb);
if(pcb!
=nuLL)
{
memset(pcb,0,sizeof(structtcp_pcb));
pcb->prio=Tcp_pRIo_noRmAL;
pcb->snd_buf=Tcp_snD_buF;//对的,别的可以先不管,这就是我们要找的东西
pcb->snd_queuelen=0;
pcb->rcv_wnd=Tcp_wnD;
pcb->rcv_ann_wnd=Tcp_wnD;
pcb->tos=0;
pcb->ttl=Tcp_TTL;
/*Thesendmssisupdatedwhenanmssoptionisreceived.*/
pcb->mss=(Tcp_mss>536)?
536:
Tcp_mss;
pcb->rto=3000/Tcp_sLow_InTeRVAL;
pcb->sa=0;
pcb->sv=3000/Tcp_sLow_InTeRVAL;
pcb->rtime=-1;
pcb->cwnd=1;
iss=tcp_next_iss();
pcb->snd_wl2=iss;
pcb->snd_nxt=iss;
pcb->snd_max=iss;
pcb->lastack=iss;
pcb->snd_lbb=iss;
pcb->tmr=tcp_ticks;
#ifLwIp_cALLbAcK_ApI
pcb->recv=tcp_recv_null;
#endif/*LwIp_cALLbAcK_ApI*/
/*InitKeepALIVetimer*/
pcb->keep_idle=Tcp_KeepIDLe_DeFAuLT;
#ifLwIp_Tcp_KeepALIVe
pcb->keep_intvl=Tcp_KeepInTVL_DeFAuLT;
pcb->keep_cnt=Tcp_KeepcnT_DeFAuLT;
#endif/*LwIp_Tcp_KeepALIVe*/pcb->polltmr=0;
pcb->keep_cnt_sent=0;
}
returnpcb;
}就是一个tcp_pcb的结构体初始化过程,使用默认值填充该结构
好了,下面接着走,该轮到tcp_write了吧
*writedataforsending(butdoesnotsenditimmediately).
*Itwaitsintheexpectationofmoredatabeingsentsoon(as
*itcansendthemmoreefficientlybycombiningthemtogether).
*Topromptthesystemtosenddatanow,calltcp_output()after
*callingtcp_write().
【src\core\tcp_out.c】
err_ttcp_write(structtcp_pcb*pcb,constvoid*data,u16_tlen,u8_tapiflags){
/*connectionisinvalidstatefordatatransmission?
*/
if(pcb->state==esTAbLIsheD||
pcb->state==cLose_wAIT||
pcb->state==sYn_senT||
pcb->state==sYn_RcVD)
{
if(len>0)
{
returntcp_enqueue(pcb,(void*)data,len,0,apiflags,nuLL,0);
}
returneRR_oK;
}
else
{
returneRR_conn;
}
}
这个函数确实够简单的了,检查pcb状态,直接入队列。
嗯,还是觉得看注释比看函数实现过瘾。
下面的这个tcp_enqueue才是个大头函数,lwip协议栈的设计与实现文档中是这么介绍的:
应用层调用tcp_write()函数以实现发送数据,接着tcp_write()函数再将控制权交给tcp_enqueue(),这个函数会在必要时将数据分割为适当大小的Tcp段,然后再把这些Tcp段放到所属连接的传输队列中【pcb->unsent】。
函数的注释是这样写的:
*enqueueeitherdataorTcpoptions(butnotboth)fortranmission
*calledbytcp_connect(),tcp_listen_input(),tcp_send_ctrl()andtcp_write().
咱们接着上面往下看,tcp_output_nagle这个函数实际上是个宏,通过预判断以决定是否调用tcp_
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- lwiptcp 接收 处理 函数
![提示](https://static.bdocx.com/images/bang_tan.gif)