朋友们听说过捷信贷款靠谱吗手机分期吗?靠谱吗?

LWIP-API 函数_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
LWIP-API 函数
上传于|0|0|暂无简介
阅读已结束,如果下载本文需要使用0下载券
想免费下载更多文档?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩3页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢关于LWIP&Raw&TCP&server&程序注意事项:stm32+enc28j60
你要是想写一个完整的TCP
server的程序,你可以把程序写成电脑向你板子发送数据,然后板子将收到的数据回发给电脑。到后期再对收到的数据进行处理以达到你板子的需求。
这个收发程序的结果应该是能够完整的将收到的数据完整的发送给电脑,不论你电脑发送的速度有多快,包有多大,一切的不成功都是你自身的原因,不要试图降低发送频率或者将包变小来解决问题。那都是治标不治本的做法。
我用的板子是stm32+enc28j60,网上有一堆移植教程,不过可能你会在移植中出现各种问题,而且有可能你遇到的问题网上还没有,我建议有时间的话看看lwip的原理,这里推荐老衲五木的《LWIP协议详解》,相当经典,看完之后至少茅斯顿开了一大半。不过有可能你没有多少耐心去看完,就只能彷徨又着急的去四处求救了。
接下来说几个注意事项:
要是初次移植LWIP,最好不要用路由器,因为那样你的板子会收到很多不是你电脑发送的数据包,同时电脑发送包的速度快了之后有的路由器就会根据自己的流量控制可能会丢弃包等,虽然对于可靠性高的TCP来说一切都不是问题,但是初学者会因为很多不明不白的现象晕很久。
最好不要用无线网来和板子通信,也就是板子插网线,你的笔记本接无线,然后两个通过路由器进行数据的传送,这样会出现你的ping很不稳定,还容易出现连接超时等。
你要是有条件就自己做一根电脑连接电脑形式的网线,直接将板子和电脑相连,这样的通信在前期是很方便和可靠的,至少你可以将基础的东西先调出来。同时要注意,要是笔记本的话,你可能插着网线又上着无线网,两个网卡工作有很大概率出现你没办法连接上你的板子。所以最好在连着板子的时候断掉无线网,或者在连接好板子并且端口之间连接上之后再打开无线网去上外网也是可以得。
最好参考官方lwip包里的APP,我在跑官方的程序的时候没有问题,但是看别人写的程序,拿来用用的时候就出了一堆问题。初级的移植相关的内容我就不说了,主要说在写TCP
server遇到的问题。
我在看别人写的收发数据的server,出现了在传输大量数据且速度很快的情况下丢失数据乃至于多出数据的情况.TCP是一种可靠性非常高的传输协议,在告诉和大量数据的情况下,就算有丢包(肯定有stm32无法应答的情况)TCP也会重传,而且有滑动窗口和阻塞窗口控制,能够知道server还能接受多大的数据包,所以一切的失败都不是TCP协议本身的问题,一定是硬件或者软件上写的有问题。
在这里先讲一个TCP整个工作的大致流程:enc28j60得到包--&ARP层(分析数据包是否更新ARP列表以及是否传输到IP层)--&IP(对收到的包进行重组,因为包太大所以发送的时候进行了分片,现在接收自然要重组)--&TCP(得到一个完整的数据包,所以你就可以在回调函数里的pbuf变量上取你想要的数据进行处理)
写server的时候尽量还是写完整一点,也就是尽量处理好错误和一些意外的情况。现在讲一下官方lwip中app的tcpecho_raw中需要注意的一些语句,这些语句你写server的时候也要注意,不然灾难不断:
当你接收到数据包的时候,比如 pbuf
*p。你会取出temp-&payload做相应的一些处理,然后可能还会做点别的事,当你做完之后你会释放这个包:pbuf_free(p),在此之前你会取出这个包指向的下一个包的地址p-&next,但还有一件事需要在pbuf_free之前完成以下,pbuf_ref(p-&next)。因为释放了p的话,p-&next的引用也会被减一,可能就导致这个包也跟着被释放了,乃至于后面串着的包都被释放了,你就会发现现象就是你发回到电脑上的数据少了很多,发送一万字节可能只有4000多。
关于tcp_recved的使用,我看到很多人写程序的时候基本上只要到了接收的回调函数里面,就在最前面加上tcp_recved(pcb,
p-&tot_len)。这个函数的作用是增加滑动窗口的大小,从而可以接收到更多字节的数据,有的同学在接受一定数量的数据后无法得到数据了就是因为没有调用这句话。但是这句话不能一概写成tcp_recved(pcb,
p-&tot_len)。大家可以看看这个函数的说明在源代码里面,这个函数应该是你处理了多少的数据包就把len取多大的字节数。而不是一味的将p-&tot_len填写进去,那样的画滑动窗口开太大了更加容易照成丢包,然后就老重发,不太好。具体可参考echo_send语句。
关于tcp_write,这个函数其实是将你的数据放到一个队列里,等以后再调用tcp_output发送出去,这里需要注意的是当你在你写了多少字节进去不一定在抓包的时候看到多少字节的数据包,因为它有可能会等write几次之后打包一起发送出去,还有个问题,在写之前最后用tcp_sndbuf(tpcb)看看还能发送多少字节的数据,这个是查看发送缓冲区的大小的函数。当你大于这个区域的时候,你就应该等待下次再发送,而能自动让你进行剩余数据发送的一个方法就是用tcp_sent的回调函数,当数据发送出去并得到了应答之后,lwip就会调用tcp_sent,你就可以在其回调函数里面写剩余的发送数据的语句了。这个最好加上,不然小心数据丢失哟。
尽量不要再lwip的应用程序里面写printf的函数,也就是串口函数等等,因为这样会拖延时间。因为拖延久了之后没有应答客户端,就会导致他重发,反正又乱了这样,我之前有次加了prinrf,就会出现收发数据一段时间以后,数据就发不出去了,发数据的时候还是一个字节一个字节往外蹦,所以需谨慎。
又想到一点,主要是lwip配置的问题:在你想要lwip发送大量数据的时候,你可能会发现发送不出来,具体点就是tcp_wirte函数返回一个错误,可能是内存的错误。那么在这里就主要是配置的问题了。打个比方:我要tcp发送12KB的数据,这里就牵扯到一个原理,write在写数据的时候首先会调用tcp_enqueue来做一些判断和数据的整理打包:&&&&&
enqueue判断数据是否大于snd_buf的缓冲区大小,所以你需要在lwipopt.h中定义TCP_SND_BUF至少比你的发送数据字节数还要大一点,不然enqueue会放弃你的数据完全不做处理--------&然后enqueue会判断等待发送的报文段还有多少,是否少于TCP_SND_QUEUELEN,所以需要将这个定义成
TCP_SND_BUF/TCP_MSS),这样肯定能满足发送需求,TCP_MSS就是一个段的大小,我定义的是TCP_MSS。------&然后enqueue会将数据打包成一个一个的报文段,格式是tcp_msg,存放在未发送的队列中等待发送。然后就是调用tcp_output发送出去。&&&&
在这里就是需要设置TCP_MSS,TCP_SND_BUF,TCP_SND_QUEUELEN三个字段,同时还要注意一个问题:在用tcp_write的时候最后一个形参为1表示将数据会复制过来进行发送,也就是说你给lwip的内存空间定义必须也要大才能存下复制过来的数据,否则你还是选择写0吧,它就会直接用这个数据的指针发送这个数据了。设置内存的空间参数是:MEM_SIZE,这个参数的大小至少要比你的最大发送数据大一些。
添加了一点新内容,排版不好,主要是没写过博客,哪位大神要是会排版可以留言教教我,等我有空了弄弄吧。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。今天看啥 热点:
#include &lwip/opt.h& //选项头文件,lwip一些配置的选项包含在opt.h,debug开启和内存大小等配置信息 &
#if LWIP_TCP /* don't build if not configured for use in lwipopts.h *//*如果在lwipopts.h没有配置LWIP_TCP这项,则不编译TCP这个文件*/ &
#include &lwip/def.h& //定义项头文件,包括一些宏 &
#include &lwip/mem.h& //内存头文件,包括一些宏,内存大小,申请内存,内存对齐 &
#include &lwip/memp.h& //内存池头文件,包含内存申请,内存释放 &
#include &lwip/snmp.h& //SNMP(Simple Network Management Protocol,简单网络管理协议),包含snmp的函数声明 &
#include &lwip/tcp.h& //包含tcp.c里面定义的函数声明和所用到的宏 &
#include &lwip/debug.h& //包含lwip debug的一些宏,开启debug &
#include &string.h& &
/* Incremented every coarse grained timer shot (typically every 500 ms). */ &
/* 增加每一个粗粒度的定时器拍摄(通常每500 ms一次)*/ &
u32_t tcp_ //定义tcp的滴答数 & & &
const u8_t tcp_backoff[13] = &
& & { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; &
&/* Times per slowtmr hits */ &
const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; &
/* The TCP PCB lists. */ &
/* TCP PCB 列表 & */ &
/** List of all TCP PCBs bound but not yet (connected || listening) */ &
/** 所有的但是还没有(连接或者监听中的TCP PCB绑定)列表*/ &
struct tcp_pcb *tcp_bound_ & &
/** List of all TCP PCBs in LISTEN state */ &
/** 所有在监听中的状态 TCP PCB列表*/ &
union tcp_listen_pcbs_t tcp_listen_ &
/** List of all TCP PCBs that are in a state in which&
&* they accept or send data. */ &
/*所有在accept或者send数据状态的TCP PCB列表 */ &
struct tcp_pcb *tcp_active_ & &
/** List of all TCP PCBs in TIME-WAIT state */ &
/*所有在等待状态中的TCP PCB*/ &
struct tcp_pcb *tcp_tw_ &
/*所有临时TCP PCB列表*/ &
struct tcp_pcb *tcp_tmp_ &
/*定义tcp计时器*/ &
static u8_t tcp_ &
/*生成新的tcp本地端口*/ &
static u16_t tcp_new_port(void); &
&* Called periodically to dispatch TCP timers.&
&*定期调用派遣TCP定时器&
tcp_tmr(void) &
& /* Call tcp_fasttmr() every 250 ms */ &
& /*每250ms调用一次tcp_fasttmr()*/ &
& tcp_fasttmr(); &
& if (++tcp_timer & 1) {//tcp_timer加1后与1 &
& & /* Call tcp_tmr() every 500 ms, i.e., every other timer&
& & & &tcp_tmr() is called. */ &
& & & &每500ms调用一次tcp_tmr(),tcp_tmr被其他的定时器调用&
& & tcp_slowtmr(); &
&* Closes the connection held by the PCB.&
&* Listening pcbs are freed and may not be referenced any more.&
&* Connection pcbs are freed if not yet connected and may not be referenced&
&* any more. If a connection is established (at least SYN received or in&
&* a closing state), the connection is closed, and put in a closing state.&
&* The pcb is then automatically freed in tcp_slowtmr(). It is therefore&
&* unsafe to reference it.&
&* @param pcb the tcp_pcb to close&
&* @return ERR_OK if connection has been closed&
&* & & & & another err_t if closing failed and pcb is not freed&
&*通过PCB关闭连接握手&
&*监听中的pcb应该被释放的,也许永远也不会被使用了&
&*连接的pcb应该被释放的,如果还没有连接或者再也没有被引用&
&*如果一个连接被建立(至少SYN已经被接收或者在一个关闭中的状态)&
&*连接被关闭了,而且输入了一个正在关闭的状态&
&*pcb然后自动在tcp_slowtmr()释放,所以引用它是不安全的&
tcp_close(struct tcp_pcb *pcb) &
& //TCP debug信息,打印pcb的状态 &
#if TCP_DEBUG &
& LWIP_DEBUGF(TCP_DEBUG, (&tcp_close: closing in &)); &
& tcp_debug_print_state(pcb-&state); &
#endif /* TCP_DEBUG */ &
& switch (pcb-&state) { &
& case CLOSED: &
& & /* Closing a pcb in the CLOSED state might seem erroneous,&
& & &* however, it is in this state once allocated and as yet unused&
& & &* and the user needs some way to free it should the need arise.&
& & &* Calling tcp_close() with a pcb that has already been closed, (i.e. twice)&
& & &* or for a pcb that has been used and then entered the CLOSED state &
& & &* is erroneous, but this should never happen as the pcb has in those cases&
& & &* been freed, and so any remaining handles are bogus. */ &
& & /*在CLOSED状态下关闭一个pcb似乎是错误的,&
& & &*尽管如此,一但在这个状态下分配了而且还没有使用所以用户需要一些办法来释放它&
& & &*调用一个已经被关闭的pcb的tcp_close(),(即2次)或者一个已经被使用了之后,进入CLOSE状态是错误的&
& & &*但作为一个在这些情况下被释放的pcb是不会存在的,因此,任何剩余的句柄都是假的&
& & err = ERR_OK;//设定返回值 &
& & TCP_RMV(&tcp_bound_pcbs, pcb);//从绑定的pcb列表中去掉pcb &
& & memp_free(MEMP_TCP_PCB, pcb);//在MEMP_TCP_PCB内存池设定释放掉的pcb对应的单元值,释放内存 &
& & pcb = NULL; //设置pcb指针指向空 &
& case LISTEN: &
& & err = ERR_OK;//设定返回值 &
& & tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb);//在tcp PCB监听列表中删除对应的pcb &
& & memp_free(MEMP_TCP_PCB_LISTEN, pcb);//在MEMP_TCP_PCB_LISTEN对应的内存池中设定需要释放的pcb单元值 &
& & pcb = NULL;//设置pcb指针指向空 &
& case SYN_SENT: &
& & err = ERR_OK;//设定返回值 &
& & tcp_pcb_remove(&tcp_active_pcbs, pcb);//在所有accept或者send数据状态的TCP PCB列表的TCP PCB列表中删除对应的pcb &
& & memp_free(MEMP_TCP_PCB, pcb);//在MEMP_TCP_PCB内存池设定释放掉的pcb对应的单元值,释放内存 &
& & pcb = NULL;//设置pcb指针指向空 &
& & snmp_inc_tcpattemptfails();//tcp尝试失败 &
& case SYN_RCVD: &
& & err = tcp_send_ctrl(pcb, TCP_FIN);//通过pcb发送对应的TCP_FIN包,表示已完成 &
& & if (err == ERR_OK) { //如果发回ERR_OK表明发送成功 &
& & & snmp_inc_tcpattemptfails();//tcp 尝试失败 &
& & & pcb-&state = FIN_WAIT_1; //pcb进入FIN_WAIT_1状态 &
& case ESTABLISHED: &
& & err = tcp_send_ctrl(pcb, TCP_FIN);//通过pcb发送对应的TCP_FIN包,表示已完成 &
& & if (err == ERR_OK) {//如果发回ERR_OK表明发送成功 &
& & & snmp_inc_tcpestabresets();//tcp 建立连接复位 &
& & & pcb-&state = FIN_WAIT_1; //pcb进入FIN_WAIT_1状态 &
& case CLOSE_WAIT: &
& & err = tcp_send_ctrl(pcb, TCP_FIN);//通过pcb发送对应的TCP_FIN包,表示已完成 &
& & if (err == ERR_OK) {//如果发回ERR_OK表明发送成功 &
& & & snmp_inc_tcpestabresets();//tcp 建立连接复位 &
& & & pcb-&state = LAST_ACK;//pcb进入LAST_ACK状态 &
& default: &
& & /* Has already been closed, do nothing. */ &
& & /* 已经被关闭,什么也不做*/ &
& & err = ERR_OK;//设置返回值 &
& & pcb = NULL;//把pcb指向NULL &
& if (pcb != NULL && err == ERR_OK) { &
& & /* To ensure all data has been sent when tcp_close returns, we have&
& & & &to make sure tcp_output doesn't fail.&
& & & &Since we don't really have to ensure all data has been sent when tcp_close&
& & & &returns (unsent data is sent from tcp timer functions, also), we don't care&
& & & &for the return value of tcp_output for now. */ &
& & /* @todo: When implementing SO_LINGER, this must be changed somehow:&
& & & &If SOF_LINGER is set, the data should be sent when tcp_close returns. */ &
& & & & 为了确认在tcp_close 返回的时候所有的数据已经被发送,我们必须确定tcp_output不是失败的,&
& & & & 从我们还没有确定在tcp_close之前不是所有的数据都被发送(没有发送的数据是从tcp计时器函数发过来的),&
& & & & 我们现在不在乎tcp_output的返回值&
& & & & todo:当正在实现SO_LINGER时,这个不知道怎么的必须被改变:&
& & & & 如果SO_LINGER被设置了,数据应该在tcp_close的时候被发送&
& & tcp_output(pcb);//发送pcb对应的包 &
&* Abandons a connection and optionally sends a RST to the remote&
&* host. &Deletes the local protocol control block. This is done when&
&* a connection is killed because of shortage of memory.&
&* @param pcb the tcp_pcb to abort&
&* @param reset boolean to indicate whether a reset should be sent&
&放弃一个连接和选择发送一个RST到远端主机&
&当一个连接因为短命的内存而挂掉,删除远端协议控制块(PCB)是要做的&
&@参数pcb:tcp_pcb终止&
&@参数reset:布尔类型表明是否要发送复位&
tcp_abandon(struct tcp_pcb *pcb, int reset) &
& u32_t seqno,//定义序列号,应答号 &
& u16_t remote_port, local_//远程端口,本地端口 &
& struct ip_addr remote_ip, local_//远程IP地址结构体,本地IP地址结构体 &
#if LWIP_CALLBACK_API &//LWIP是否要使用回调API &
& void (* errf)(void *arg, err_t err);//定义回调函数指针 &
#endif /* LWIP_CALLBACK_API */ &
& void *errf_ &
& /* Figure out on which TCP PCB list we are, and remove us. If we&
& & &are in an active state, call the receive function associated with&
& & &the PCB with a NULL argument, and send an RST to the remote end. */ &
& & 找出我们的pcb在TCP PCB列表那个位置后删除,如果我们在一个激活状态,&
& & 调用pcb NULL参数的接收函数协助处理,&
& & 并发送一个RST到远程终端&
& if (pcb-&state == TIME_WAIT) { //如果pcb状态值是TIME_WAIT &
& & tcp_pcb_remove(&tcp_tw_pcbs, pcb);//从time-wait等待状态列表中删除pcb &
& & memp_free(MEMP_TCP_PCB, pcb);//删除pcb内存 &
& } else {//否则 &
& & seqno = pcb-&snd_//序列号指向发送下一个 &
& & ackno = pcb-&rcv_//应答好指向接收到的下一个 &
& & ip_addr_set(&local_ip, &(pcb-&local_ip));//设置pcb中的本地地址 &
& & ip_addr_set(&remote_ip, &(pcb-&remote_ip));//设置pcb中的远端地址 &
& & local_port = pcb-&local_ &
& & remote_port = pcb-&remote_ &
#if LWIP_CALLBACK_API &
& & errf = pcb-&//指针指向回调函数 &
#endif /* LWIP_CALLBACK_API */ &
& & errf_arg = pcb-&callback_//回调参数 &
& & tcp_pcb_remove(&tcp_active_pcbs, pcb);//把pcb重激活的tcp pcb列表中删除 &
& & if (pcb-&unacked != NULL) {//发送还没有回答? &
& & & tcp_segs_free(pcb-&unacked);//释放未应答段 &
& & if (pcb-&unsent != NULL) {//还没有发送? &
& & & tcp_segs_free(pcb-&unsent);//释放还没有发送段 &
#if TCP_QUEUE_OOSEQ & &//TCP队列乱序 &
& & if (pcb-&ooseq != NULL) {//队列乱? &
& & & tcp_segs_free(pcb-&ooseq);//释放乱队列 &
#endif /* TCP_QUEUE_OOSEQ */ &
& & memp_free(MEMP_TCP_PCB, pcb);//释放pcb &
& & TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);//调用回调函数,传入终止错误参数 &
& & if (reset) {//复位? &
& & & LWIP_DEBUGF(TCP_RST_DEBUG, (&tcp_abandon: sending RST\n&));//打印发送RST信息 &
& & & tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);//tcp发送复位信息包 &
&* Binds the connection to a local portnumber and IP address. If the&
&* IP address is not given (i.e., ipaddr == NULL), the IP address of&
&* the outgoing network interface is used instead.&
&* @param pcb the tcp_pcb to bind (no check is done whether this pcb is&
&* & & & &already bound!)&
&* @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind&
&* & & & &to any local address&
&* @param port the local port to bind to&
&* @return ERR_USE if the port is already in use&
&* & & & & ERR_OK if bound&
/*绑定一个连接的本地IP和端口.如果IP地址没有,传出去的接口IP会被替代&
&*参数pcb:绑定的tcp_pcb(不检查是否这个pcb已经绑定)&
&*参数ipaddr:本地IP地址绑定(用IP_ADDR_ANY绑定任何本地IP&
&*参数port: 本地端口绑定&
&*返回ERR_USE如果端口已经被使用,返回ERR_OK如果绑定好&
tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) &
& struct tcp_pcb * //定义cpcb &
& LWIP_ERROR(&tcp_bind: can only bind in state CLOSED&, pcb-&state == CLOSED, return ERR_ISCONN); &
& if (port == 0) { //端口为0则从本地找一个端口 &
& & port = tcp_new_port(); &
& /* Check if the address already is in use. */ &
& /* Check the listen pcbs. */ &
& //检查是不是地址已经在使用 &
& for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs. &
& & & cpcb != NULL; cpcb = cpcb-&next) { &
& & if (cpcb-&local_port == port) {//端口是否在使用 &
& & & if (ip_addr_isany(&(cpcb-&local_ip)) || &
& & & & & ip_addr_isany(ipaddr) || &
& & & & & ip_addr_cmp(&(cpcb-&local_ip), ipaddr)) { &
& & & & return ERR_USE;//返回在使用 &
& /* Check the connected pcbs. */ &
& /*检查已连接的PCB*/ &
& for(cpcb = tcp_active_ &
& & & cpcb != NULL; cpcb = cpcb-&next) { &
& & if (cpcb-&local_port == port) {//端口是否在使用 &
& & & if (ip_addr_isany(&(cpcb-&local_ip)) || &
& & & & & ip_addr_isany(ipaddr) || &
& & & & & ip_addr_cmp(&(cpcb-&local_ip), ipaddr)) { &
& & & & return ERR_USE;//返回在使用 &
& /* Check the bound, not yet connected pcbs. */ &
& /* 检查绑定,但没有连接的PCB*/ &
& for(cpcb = tcp_bound_ cpcb != NULL; cpcb = cpcb-&next) { &
& & if (cpcb-&local_port == port) {//端口是否在使用 &
& & & if (ip_addr_isany(&(cpcb-&local_ip)) || &
& & & & & ip_addr_isany(ipaddr) || &
& & & & & ip_addr_cmp(&(cpcb-&local_ip), ipaddr)) { &
& & & & return ERR_USE;//返回在使用 &
& /* @todo: until SO_REUSEADDR is implemented (see task #6995 on savannah),&
& &* we have to check the pcbs in TIME-WAIT state, also: */ &
& /*todo:直到SO_REUSEADDR被完成(看任务#6995),&
& 我们也必须检查pcb是不是在 TIME-WAIT状态&
& for(cpcb = tcp_tw_ cpcb != NULL; cpcb = cpcb-&next) { &
& & if (cpcb-&local_port == port) {//端口是否在使用 &
& & & if (ip_addr_cmp(&(cpcb-&local_ip), ipaddr)) { &
& & & & return ERR_USE;//返回在使用 &
& if (!ip_addr_isany(ipaddr)) {//检查是否为所有本地IP地址 &
& & pcb-&local_ip = * &
& pcb-&local_port =//设定本地端口 &
& TCP_REG(&tcp_bound_pcbs, pcb);//注册绑定的pcb &
& LWIP_DEBUGF(TCP_DEBUG, (&tcp_bind: bind to port %&U16_F&\n&, port)); &
& return ERR_OK;//返回绑定成功 &
#if LWIP_CALLBACK_API &
&* Default accept callback if no accept callback is specified by the user.&
& *如果没有用户指定的接受回调,默认接受回调&
static err_t &
tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err) &
& LWIP_UNUSED_ARG(arg);//没使用的参数 &
& LWIP_UNUSED_ARG(pcb);//没使用的参数 &
& LWIP_UNUSED_ARG(err);//没使用的参数 &
& return ERR_ABRT;//返回终止 &
#endif /* LWIP_CALLBACK_API */ &
&* Set the state of the connection to be LISTEN, which means that it&
&* is able to accept incoming connections. The protocol control block&
&* is reallocated in order to consume less memory. Setting the&
&* connection to LISTEN is an irreversible process.&
&* @param pcb the original tcp_pcb&
&* @param backlog the incoming connections queue limit&
&* @return tcp_pcb used for listening, consumes less memory.&
&* @note The original tcp_pcb is freed. This function therefore has to be&
&* & & & called like this:&
&* & & & & & & tpcb = tcp_listen(tpcb);&
&* &设置连接状态来监听,这意味着它可以接受进来的连接,&
&* &协议控制块重新分配是为了减少内存开销,&
&* &设置连接来监听是一个不可逆的过程。&
struct tcp_pcb * &
tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) &
& struct tcp_pcb_listen *//定义监听协议控制块 &
& LWIP_UNUSED_ARG(backlog);//不用参数 &
& LWIP_ERROR(&tcp_listen: pcb already connected&, pcb-&state == CLOSED, return NULL); &
& //判断pcb状态是否关闭 &
& /* already listening? */ &
& //已经在监听中? &
& if (pcb-&state == LISTEN) { &
& &//返回 &
& lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN);//分配MEMP_TCP_PCB_LISTEN内存 &
& if (lpcb == NULL) {//分配不成功 &
& & return NULL;//退出 &
& lpcb-&callback_arg = pcb-&callback_//回调参数 &
& lpcb-&local_port = pcb-&local_//本地端口 &
& lpcb-&state = LISTEN;//标志为监听状态 &
& lpcb-&so_options = pcb-&so_//Socket选项 &
& lpcb-&so_options |= SOF_ACCEPTCONN;//socket 已经监听 &
& lpcb-&ttl = pcb-&//存活时间 &
& lpcb-&tos = pcb-&//服务类型 &
& ip_addr_set(&lpcb-&local_ip, &pcb-&local_ip);//设置本地IP &
& TCP_RMV(&tcp_bound_pcbs, pcb);//把pcb从tcp绑定列表中删除 &
& memp_free(MEMP_TCP_PCB, pcb);//释放空间 &
#if LWIP_CALLBACK_API &
& lpcb-&accept = tcp_accept_ //设置接受函数为空 &
#endif /* LWIP_CALLBACK_API */ &
#if TCP_LISTEN_BACKLOG &
& lpcb-&accepts_pending = 0;//接受挂起清空 &
& lpcb-&backlog = (backlog ? backlog : 1);//累积&0?否则1 &
#endif /* TCP_LISTEN_BACKLOG */ &
& TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb);//注册lpcb进监听列表 &
& return (struct tcp_pcb *)//返回监听的块 &
&* Update the state that tracks the available window space to advertise.&
&* Returns how much extra window would be advertised if we sent an&
&* update now.&
&*更新状态这个追踪了允许可用的窗口空间来发布 &
&*如果我们现在开始发送一个更新将返回多少额外的窗体将发布&
u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)//TCP 更新接收发布窗口 &
& u32_t new_right_edge = pcb-&rcv_nxt + pcb-&rcv_//下一个序列号+接收窗口 &
& if (TCP_SEQ_GEQ(new_right_edge, pcb-&rcv_ann_right_edge + pcb-&mss)) {//比较是否越界 &
& & /* we can advertise more window */ &
& & /* 我们可以发布更多窗口*/ &
& & pcb-&rcv_ann_wnd = pcb-&rcv_//接收发布窗口设置为接收窗口 &
& & return new_right_edge - pcb-&rcv_ann_right_//得到剩下的发布窗口 &
& } else { &
& & if (TCP_SEQ_GT(pcb-&rcv_nxt, pcb-&rcv_ann_right_edge)) {//如果期待的下一个序列号大于发布边界 &
& & & /* Can happen due to other end sending out of advertised window,&
& & & &* but within actual available (but not yet advertised) window */ &
& & & & 可以发生在另一端发送超出发布窗口,但是在实际允许(但还没有发布的)窗口&
& & & &*/ &
& & & pcb-&rcv_ann_wnd = 0;//发布窗口置0 &
& & } else { &
& & & /* keep the right edge of window constant */ &
& & & /*保持正确的不变窗口边界*/ &
& & & pcb-&rcv_ann_wnd = pcb-&rcv_ann_right_edge - pcb-&rcv_ &
& & return 0; &
&* This function should be called by the application when it has&
&* processed the data. The purpose is to advertise a larger window&
&* when the data has been processed.&
&* @param pcb the tcp_pcb for which data is read&
&* @param len the amount of bytes that have been read by the application&
&*这个函数应该被已经处理数据的应用程序调用。目的是当数据已经被处理后发布更大的窗口&
&*参数pcb:数据已经被读的tcp_pcb&
&*参数len:已经被应用程序读取的数据量&
tcp_recved(struct tcp_pcb *pcb, u16_t len) &
& int wnd_//定义窗口膨胀变量 &
& LWIP_ASSERT(&tcp_recved: len would wrap rcv_wnd\n&, &
& & & & & & & len &= 0xffff - pcb-&rcv_wnd ); &
& pcb-&rcv_wnd +=//接收到的窗口加len &
& if (pcb-&rcv_wnd & TCP_WND)//大于TCP_WND? &
& & pcb-&rcv_wnd = TCP_WND;//职位最大的窗口值 &
& wnd_inflation = tcp_update_rcv_ann_wnd(pcb);//更新发布窗口,返回剩下的值 &
& /* 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) */ &
& /*如果在正确的窗口边缘出现改变是有意义的(默认的水印是TCP_WND/2),然后现在发送一个明确的更新。&
& &* 另外等待在正常情况事件下(或者在之后更多的可用窗口)发送一个包&
& if (wnd_inflation &= TCP_WND_UPDATE_THRESHOLD) //返回的值大于TCP窗口更新的临界值 &
& & tcp_ack_now(pcb);//tcp应答 &
& LWIP_DEBUGF(TCP_DEBUG, (&tcp_recved: recveived %&U16_F& bytes, wnd %&U16_F& (%&U16_F&).\n&, &
& & & & &len, pcb-&rcv_wnd, TCP_WND - pcb-&rcv_wnd)); &
&* A nastly hack featuring 'goto' statements that allocates a&
&* new TCP local port.&
&* @return a new (free) local TCP port number&
&*声明一个分配新TCP本地端口,返回一个新的可用的本地TCP端口&
static u16_t &
tcp_new_port(void) &
& struct tcp_pcb * &
#ifndef TCP_LOCAL_PORT_RANGE_START & &
#define TCP_LOCAL_PORT_RANGE_START 4096//端口范围开始 &
#define TCP_LOCAL_PORT_RANGE_END & 0x7fff//端口范围结束 &
& static u16_t port = TCP_LOCAL_PORT_RANGE_START;//开始端口 &
& if (++port & TCP_LOCAL_PORT_RANGE_END) {//是否超出范围 &
& & port = TCP_LOCAL_PORT_RANGE_START;//超出,则回到开始 &
& for(pcb = tcp_active_ pcb != NULL; pcb = pcb-&next) {//在激活的列表中循环尝试 &
& & if (pcb-&local_port == port) {//已被使用 &
& & &//下一个 &
& for(pcb = tcp_tw_ pcb != NULL; pcb = pcb-&next) {//在等待的列表中循环尝试 &
& & if (pcb-&local_port == port) {//已被使用 &
& & &//下一个 &
& for(pcb = (struct tcp_pcb *)tcp_listen_pcbs. pcb != NULL; pcb = pcb-&next) {//在监听的列表中循环尝试 &
& & if (pcb-&local_port == port) {//已被使用 &
& & &//下一个 &
&* Connects to another host. The function given as the &connected&&
&* argument will be called when the connection has been established.&
&* @param pcb the tcp_pcb used to establish the connection&
&* @param ipaddr the remote ip address to connect to&
&* @param port the remote tcp port to connect to&
&* @param connected callback function to call when connected (or on error)&
&* @return ERR_VAL if invalid arguments are given&
&* & & & & ERR_OK if connect request has been sent&
&* & & & & other err_t values if connect request couldn't be sent&
&*连接到其他的主机,当连接已经建立,connected作为参数将被调用&
&*@参数 pcb:被用来作为建立连接的tcp_pcb&
&*@参数 ipaddr:连接到的远程IP地址&
&*@参数 port:连接到的远程tcp端口&
&*@参数 connected:当连接了(或者出错误)的回调函数&
&*如果传入的是非法的参数返回ERR_VAL&
&*如果连接请求已经发送放回ERR_OK&
&*如果连接请求没有发送返回其他的err_t值&
tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port, &
& & & err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)) &
& LWIP_ERROR(&tcp_connect: can only connected from state CLOSED&, pcb-&state == CLOSED, return ERR_ISCONN); &
& LWIP_DEBUGF(TCP_DEBUG, (&tcp_connect to port %&U16_F&\n&, port)); &
& if (ipaddr != NULL) {//如果传入的地址不为空 &
& & pcb-&remote_ip = *//远程ip赋值 &
& } else { &
& & return ERR_VAL;//返回错误值 &
& pcb-&remote_port =//设置远程端口 &
& if (pcb-&local_port == 0) {//本地端口为0 &
& & pcb-&local_port = tcp_new_port();//申请新端口 &
& iss = tcp_next_iss();//计算一个新的初始化序列号给新的连接 &
& pcb-&rcv_nxt = 0;//接收的下一个为0 &
& pcb-&snd_nxt =//发送的下一个为初始化序列号 &
& pcb-&lastack = iss - 1;//ack减一 &
& pcb-&snd_lbb = iss - 1;// 下一个字节序列号缓冲 &
& pcb-&rcv_wnd = TCP_WND;//接收窗口数 &
& pcb-&rcv_ann_wnd = TCP_WND;//接收发布窗口数 &
& pcb-&rcv_ann_right_edge = pcb-&rcv_//发布正确边缘 &
& pcb-&snd_wnd = TCP_WND;//发送窗口数 &
& /* As initial send MSS, we use TCP_MSS but limit it to 536.&
& & &The send MSS is updated when an MSS option is received. */ &
& /* 作为初始化发送最大段大小,我们使用TCP_MSS但是限制在536.&
& & &当一个 最大段大小选项被接收,发送的最大段大小就被更新*/ &
& pcb-&mss = (TCP_MSS & 536) ? 536 : TCP_MSS; &
#if TCP_CALCULATE_EFF_SEND_MSS &
& pcb-&mss = tcp_eff_send_mss(pcb-&mss, ipaddr);//计算有效发送的最大段大小 &&
#endif /* TCP_CALCULATE_EFF_SEND_MSS */ &
& pcb-&cwnd = 1;//避免拥挤 &
& pcb-&ssthresh = pcb-&mss * 10;//控制值 &
& pcb-&state = SYN_SENT;//设置同步发送 &
#if LWIP_CALLBACK_API & &
& pcb-&connected =//连接回调函数 &
#endif /* LWIP_CALLBACK_API */ &
& TCP_RMV(&tcp_bound_pcbs, pcb);//从绑定列表中删除pcb &
& TCP_REG(&tcp_active_pcbs, pcb);//注册激活的pcb到激活列表 &
& snmp_inc_tcpactiveopens();//开启tcp激活 &
& //pcb假如tcp队列 &
& ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, TF_SEG_OPTS_MSS &
#if LWIP_TCP_TIMESTAMPS &
& & & & & & & & & & | TF_SEG_OPTS_TS &
& & & & & & & & & & ); &
& if (ret == ERR_OK) { //OK? &
& & tcp_output(pcb);//发送数据包 &
&//返回结果 &
&* Called every 500 ms and implements the retransmission timer and the timer that&
&* removes PCBs that have been in TIME-WAIT for enough time. It also increments&
&* various timers such as the inactivity timer in each PCB.&
&* Automatically called from tcp_tmr().&
&* &每500ms调用和实施传播计时器,计时器删除已经足够时间在TIME-WAIT的PCB,&
&* &这个也增加各种计时器,例如在每个PCB中的休止状态的计时器&
tcp_slowtmr(void) &
& struct tcp_pcb *pcb, *pcb2, * &
& u16_t eff_// 有效窗口 &
& u8_t pcb_ & & &/* flag if a PCB should be removed *//*一个PCB应该被移除的标记*/ &
& err = ERR_OK; &
& ++tcp_//tcp滴答数+1 &
& /* Steps through all of the active PCBs. */ &
& /*所有激活中的PCB*/ &
& prev = NULL; &
& pcb = tcp_active_ &
& if (pcb == NULL) { &
& & LWIP_DEBUGF(TCP_DEBUG, (&tcp_slowtmr: no active pcbs\n&)); &
& while (pcb != NULL) {//遍历激活的pcb列表 &
& & LWIP_DEBUGF(TCP_DEBUG, (&tcp_slowtmr: processing active pcb\n&)); &
& & LWIP_ASSERT(&tcp_slowtmr: active pcb-&state != CLOSED\n&, pcb-&state != CLOSED); &
& & LWIP_ASSERT(&tcp_slowtmr: active pcb-&state != LISTEN\n&, pcb-&state != LISTEN); &
& & LWIP_ASSERT(&tcp_slowtmr: active pcb-&state != TIME-WAIT\n&, pcb-&state != TIME_WAIT); &
& & pcb_remove = 0; &
& & if (pcb-&state == SYN_SENT && pcb-&nrtx == TCP_SYNMAXRTX) {//如果状态为SYN_SENT而且pcb传播编号是TCP_SYNMAXRTX &
& & & ++pcb_//移除计数加1 &
& & & LWIP_DEBUGF(TCP_DEBUG, (&tcp_slowtmr: max SYN retries reached\n&)); &
& & else if (pcb-&nrtx == TCP_MAXRTX) {//pcb传播编号是TCP_SYNMAXRTX &
& & & ++pcb_//移除计数加1 &
& & & LWIP_DEBUGF(TCP_DEBUG, (&tcp_slowtmr: max DATA retries reached\n&)); &
& & } else { &
& & & if (pcb-&persist_backoff & 0) { &
& & & & /* If snd_wnd is zero, use persist timer to send 1 byte probes&
& & & & &* instead of using the standard retransmission mechanism. */ &
& & & & /* 如果发送窗口是0,持续使用计时器发送1字节使用标准传播编号机制探索替代 &*/ &
& & & & pcb-&persist_cnt++;//持续计时器计数 &
& & & & if (pcb-&persist_cnt &= tcp_persist_backoff[pcb-&persist_backoff-1]) {//tcp持续备值 &
& & & & & pcb-&persist_cnt = 0; &
& & & & & if (pcb-&persist_backoff & sizeof(tcp_persist_backoff)) {//如果pcb持续备值小雨tcp_persist_backoff的大小 &
& & & & & & pcb-&persist_backoff++;//加1 &
& & & & & } &
& & & & & tcp_zero_window_probe(pcb);//发送持续计时器零窗口探头 &
& & & & } &
& & & } else { &
& & & & /* Increase the retransmission timer if it is running */ &
& & & & /* 如果重传计数器在跑,则增加*/ &
& & & & if(pcb-&rtime &= 0) &
& & & & & ++pcb-& &
& & & & if (pcb-&unacked != NULL && pcb-&rtime &= pcb-&rto) {// &
& & & & & /* Time for a retransmission. */ &
& & & & & /* 转播时间 */ &
& & & & & LWIP_DEBUGF(TCP_RTO_DEBUG, (&tcp_slowtmr: rtime %&S16_F &
& & & & & & & & & & & & & & & & & & & & pcb-&rto %&S16_F&\n&, &
& & & & & & & & & & & & & & & & & & & pcb-&rtime, pcb-&rto)); &
& & & & & /* Double retransmission time-out unless we are trying to&
& & & & & &* connect to somebody (i.e., we are in SYN_SENT). */ &
& & & & & /*双重转播超时出发我们尝试连接到别人那里(也就是,我们在SYN_SENT状态)&
& & & & & &*&
& & & & & &*/ &
& & & & & if (pcb-&state != SYN_SENT) {//pcb不在SYN_SENT &
& & & & & & pcb-&rto = ((pcb-&sa && 3) + pcb-&sv) && tcp_backoff[pcb-&nrtx];//计算出重发时间 &
& & & & & } &
& & & & & /* Reset the retransmission timer. */ &
& & & & & /*重置重发计时器*/ &
& & & & & pcb-&rtime = 0; &
& & & & & /* Reduce congestion window and ssthresh. */ &
& & & & & /* 减少拥挤窗口和阀门值*/ &
& & & & & eff_wnd = LWIP_MIN(pcb-&cwnd, pcb-&snd_wnd);//计算有效窗口 &
& & & & & pcb-&ssthresh = eff_wnd && 1;//有效值右移1位 &
& & & & & if (pcb-&ssthresh & pcb-&mss) {//阀门值小于最大段大小? &
& & & & & & pcb-&ssthresh = pcb-&mss * 2; &
& & & & & } &
& & & & & pcb-&cwnd = pcb-&//最大段大小赋给拥挤窗口 &
& & & & & LWIP_DEBUGF(TCP_CWND_DEBUG, (&tcp_slowtmr: cwnd %&U16_F &
& & & & & & & & & & & & & & & & & & & && ssthresh %&U16_F&\n&, &
& & & & & & & & & & & & & & & & & & & &pcb-&cwnd, pcb-&ssthresh)); &
& & & & & /* The following needs to be called AFTER cwnd is set to one&
& & & & & & &mss - STJ */ &
& & & & & /*在调用AFTER拥挤窗口被设置为一个最大段大小- STJ时下面需要被调用&
& & & & & */ &
& & & & & tcp_rexmit_rto(pcb);//为重发重新入队所有的未应答段 &
& & & & } &
& & /* Check if this PCB has stayed too long in FIN-WAIT-2 */ &
& & /* 检测如果这个PCB已经在FIN-WAIT-2状态下等太久了 */ &
& & if (pcb-&state == FIN_WAIT_2) {//检测状态 &
& & & if ((u32_t)(tcp_ticks - pcb-&tmr) & &
& & & & & TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {//tcp滴答数减去计时器的计数 是否大于等待的时间除以粗粒超时? &
& & & & ++pcb_//删除多一个pcb &
& & & & LWIP_DEBUGF(TCP_DEBUG, (&tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n&)); &
& & /* Check if KEEPALIVE should be sent */ &
& & /* 检测如果KEEPALIVE被发送了*/ &
& & if((pcb-&so_options & SOF_KEEPALIVE) && &&
& & & &((pcb-&state == ESTABLISHED) || &&
& & & & (pcb-&state == CLOSE_WAIT))) {//在SOF_KEEPALIVE的情况下且是ESTABLISHED或CLOSE_WAIT状态 &
#if LWIP_TCP_KEEPALIVE &
& & & if((u32_t)(tcp_ticks - pcb-&tmr) & &&
& & & & &(pcb-&keep_idle + (pcb-&keep_cnt*pcb-&keep_intvl)) &
& & & & &/ TCP_SLOW_INTERVAL)//如果是KEEPALIVE被打开,允许计数keep alive的间隔 &
#else & & & &
& & & if((u32_t)(tcp_ticks - pcb-&tmr) & &&
& & & & &(pcb-&keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)//最大的闲置Keep alive &
#endif /* LWIP_TCP_KEEPALIVE */ &
& & & & LWIP_DEBUGF(TCP_DEBUG, (&tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %&U16_F&.%&U16_F&.%&U16_F&.%&U16_F&.\n&, &
& & & & & & & & & & & & & & & & ip4_addr1(&pcb-&remote_ip), ip4_addr2(&pcb-&remote_ip), &
& & & & & & & & & & & & & & & & ip4_addr3(&pcb-&remote_ip), ip4_addr4(&pcb-&remote_ip))); &
& & & & &&
& & & & tcp_abort(pcb);//终止pcb &
#if LWIP_TCP_KEEPALIVE &
& & & else if((u32_t)(tcp_ticks - pcb-&tmr) & &&
& & & & & & & (pcb-&keep_idle + pcb-&keep_cnt_sent * pcb-&keep_intvl) &
& & & & & & & / TCP_SLOW_INTERVAL)//如果是KEEPALIVE被打开,允许发送计数keep alive的间隔 &
& & & else if((u32_t)(tcp_ticks - pcb-&tmr) & &&
& & & & & & & (pcb-&keep_idle + pcb-&keep_cnt_sent * TCP_KEEPINTVL_DEFAULT) &&
& & & & & & & / TCP_SLOW_INTERVAL)//最大的闲置发送计数*默认Keep alive间隔 &
#endif /* LWIP_TCP_KEEPALIVE */ &
& & & & tcp_keepalive(pcb);//keepalive pcb &
& & & & pcb-&keep_cnt_sent++;//计数加1 &
& & /* If this PCB has queued out of sequence data, but has been&
& & & &inactive for too long, will drop the data (it will eventually&
& & & &be retransmitted). */ &
& & /* 如果这个PCB 有队列超出序列的数据,但是已经不活跃太长一段时间了,&
& & & & 将终止数据(它最终将被重传)*/ &
#if TCP_QUEUE_OOSEQ & & &
& & if (pcb-&ooseq != NULL && &
& & & & (u32_t)tcp_ticks - pcb-&tmr &= pcb-&rto * TCP_OOSEQ_TIMEOUT) { /* 接收超出序列的段 */ &
& & & tcp_segs_free(pcb-&ooseq);//释放超出序列段 &
& & & pcb-&ooseq = NULL; &
& & & LWIP_DEBUGF(TCP_CWND_DEBUG, (&tcp_slowtmr: dropping OOSEQ queued data\n&)); &
#endif /* TCP_QUEUE_OOSEQ */ &
& & /* Check if this PCB has stayed too long in SYN-RCVD */ &
& & /* 检测如果这个PCB已经在SYN-RCVD状态太长时间了 */ &
& & if (pcb-&state == SYN_RCVD) { &
& & & if ((u32_t)(tcp_ticks - pcb-&tmr) & &
& & & & & TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) {//超时了? &
& & & & ++pcb_//移除加1 &
& & & & LWIP_DEBUGF(TCP_DEBUG, (&tcp_slowtmr: removing pcb stuck in SYN-RCVD\n&)); &
& & /* Check if this PCB has stayed too long in LAST-ACK */ &
& & /* 检测如果这个PCB已经在LAST-ACK太长时间了 */ &
& & if (pcb-&state == LAST_ACK) { &
& & & if ((u32_t)(tcp_ticks - pcb-&tmr) & 2 * TCP_MSL / TCP_SLOW_INTERVAL) {//超时了? &
& & & & ++pcb_//移除数加1 &
& & & & LWIP_DEBUGF(TCP_DEBUG, (&tcp_slowtmr: removing pcb stuck in LAST-ACK\n&)); &
& & /* If the PCB should be removed, do it. */ &
& & /* 如果PCB应该被移除,执行 */ &
& & if (pcb_remove) { &
& & & tcp_pcb_purge(pcb); & & &//清理一个TCP PCB &
& & & /* Remove PCB from tcp_active_pcbs list. */ &
& & & /* 把PCB从激活列表里移除. */ &
& & & if (prev != NULL) {//前一个为空? &
& & & & LWIP_ASSERT(&tcp_slowtmr: middle tcp != tcp_active_pcbs&, pcb != tcp_active_pcbs); &
& & & & prev-&next = pcb-&//下一个指向pcb的next &
& & & } else { &
& & & & /* This PCB was the first. */ &
& & & & /* 这个PCB是第一个. */ &
& & & & LWIP_ASSERT(&tcp_slowtmr: first pcb == tcp_active_pcbs&, tcp_active_pcbs == pcb); &
& & & & tcp_active_pcbs = pcb-&//直接把tcp_active_pcbs队列执行pcb的下一个 &
& & & TCP_EVENT_ERR(pcb-&errf, pcb-&callback_arg, ERR_ABRT);//TCP错误发生事件 &
& & & pcb2 = pcb-&//pcb2指向pcb的next &
& & & memp_free(MEMP_TCP_PCB, pcb);//释放pcb &
& & & pcb = pcb2;//pcb指向往下的一个 &
& & } else { &
& & & /* We check if we should poll the connection. */ &
& & & /* 我们检测是否我们应该调查连接. */ &
& & & ++pcb-&//调查计时器加1 &
& & & if (pcb-&polltmr &= pcb-&pollinterval) {//计数器大于调查间隔 &
& & & & pcb-&polltmr = 0;//调查计数器置0 &
& & & & LWIP_DEBUGF(TCP_DEBUG, (&tcp_slowtmr: polling application\n&)); &
& & & & TCP_EVENT_POLL(pcb, err);//TCP调查事件 &
& & & & if (err == ERR_OK) {//错误? &
& & & & & tcp_output(pcb);//发送pcb数据 &
& & & & } &
& & & prev =//前一个指向pcb &
& & & pcb = pcb-&//pcb指向pcb的下一个 &
& /* Steps through all of the TIME-WAIT PCBs. */ &
& /* 遍历所有的TIME-WAI 状态的PCB. */ &
& prev = NULL; & & &
& pcb = tcp_tw_//pcb指向time wait pcb列表 &
& while (pcb != NULL) { &
& & LWIP_ASSERT(&tcp_slowtmr: TIME-WAIT pcb-&state == TIME-WAIT&, pcb-&state == TIME_WAIT); &
& & pcb_remove = 0;//移除计数设置0 &
& & /* Check if this PCB has stayed long enough in TIME-WAIT */ &
& & /* 检测是否这个PCB已经在TIME-WAIT状态足够长时间 */ &
& & if ((u32_t)(tcp_ticks - pcb-&tmr) & 2 * TCP_MSL / TCP_SLOW_INTERVAL) { &
& & & ++pcb_//pcb移除技术加1 &
& & /* If the PCB should be removed, do it. */ &
& & /* 如果PCB应该被移除,动手吧. */ &
& & if (pcb_remove) { &
& & & tcp_pcb_purge(pcb); //清理pcb &
& & & /* Remove PCB from tcp_tw_pcbs list. */ &
& & & /* 吧PCB从tcp_tw_pcbs列表中移除. */ &
& & & if (prev != NULL) { &
& & & & LWIP_ASSERT(&tcp_slowtmr: middle tcp != tcp_tw_pcbs&, pcb != tcp_tw_pcbs); &
& & & & prev-&next = pcb-&//摘除pcb &
& & & } else { &
& & & & /* This PCB was the first. */ &
& & & & /* 这是第一个PCB. */ &
& & & & LWIP_ASSERT(&tcp_slowtmr: first pcb == tcp_tw_pcbs&, tcp_tw_pcbs == pcb); &
& & & & tcp_tw_pcbs = pcb-&//摘除 &
& & & pcb2 = pcb-&//pcb2指向pcb的下一个 &
& & & memp_free(MEMP_TCP_PCB, pcb);//释放pcb &
& & & pcb = pcb2; &
& & } else {//否则不应该移除 &
& & & prev =//前面的指针指向pcb &
& & & pcb = pcb-&//pcb指向下一个 &
&* Is called every TCP_FAST_INTERVAL (250 ms) and process data previously&
&* &refused& by upper layer (application) and sends delayed ACKs.&
&* Automatically called from tcp_tmr().&
&* &叫每个tcp快速区间(250毫秒)和过程数据之前&拒绝&,上层(应用程序)和发送延迟ack。&
&* &每个TCP_FAST_INTERVAL (250 ms)和处理的数据之前被拒绝被上层(应用程序)和发送延迟ACK调用&
&* &自动从tcp_tmr()调用&
tcp_fasttmr(void) &
& struct tcp_pcb * &
& for(pcb = tcp_active_ pcb != NULL; pcb = pcb-&next) { //遍历tcp_active_pcbs列表 &
& & /* If there is data which was previously &refused& by upper layer */ &
& & /* 如果有数据提前被上层拒绝 & */ &
& & if (pcb-&refused_data != NULL) { &
& & & /* Notify again application with data previously received. */ &
& & & /* 再次通知应用数据提前接收. */ &
& & & err_ &
& & & LWIP_DEBUGF(TCP_INPUT_DEBUG, (&tcp_fasttmr: notify kept packet\n&)); &
& & & TCP_EVENT_RECV(pcb, pcb-&refused_data, ERR_OK, err);// &
& & & if (err == ERR_OK) { &
& & & & pcb-&refused_data = NULL;//拒绝数据置空 &
& & /* send delayed ACKs */ & &
& & /* 发送延迟ACK */ & &
& & if (pcb-&flags & TF_ACK_DELAY) { &
& & & LWIP_DEBUGF(TCP_DEBUG, (&tcp_fasttmr: delayed ACK\n&)); &
& & & tcp_ack_now(pcb);//输出应答PCB包 &
& & & pcb-&flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);//设置标志位,取消延迟ACK和立即ACK &
&* Deallocates a list of TCP segments (tcp_seg structures).&
&* @param seg tcp_seg list of TCP segments to free&
&* @return the number of pbufs that were deallocated&
&* 释放一个TCP段(tcp_seg结构)列表的分配&
&* @参数seg tcp_seg: 要十分的TCP段列表&
&* @返回 一个被释放掉的phufs的数量&
tcp_segs_free(struct tcp_seg *seg) &
& u8_t count = 0;//置0 &
& struct tcp_seg *//tcp段下一个 &
& while (seg != NULL) {//段为空? &
& & next = seg-&//下一个 &
& & count += tcp_seg_free(seg);//释放, &
& & seg =//段指向下一个 &
&//返回计数 &
&* Frees a TCP segment (tcp_seg structure).&
&* @param seg single tcp_seg to free&
&* @return the number of pbufs that were deallocated&
&* &释放一个TCP段(tcp_seg 结构)&
&* @参数 seg:单个要释放的tcp_seg&
&* @返回 pbuf被释放的数量&
tcp_seg_free(struct tcp_seg *seg) &
& u8_t count = 0; &
& if (seg != NULL) {//段为空? &
& & if (seg-&p != NULL) {//seg-&p这段buffer包括了数据+TCP头,为空? &
& & & count = pbuf_free(seg-&p);//释放 &
#if TCP_DEBUG &
& & & seg-&p = NULL;//置空 &
#endif /* TCP_DEBUG */ &
& & memp_free(MEMP_TCP_SEG, seg);//释放seg段 &
&//返回释放数量 &
&* Sets the priority of a connection.&
&* @param pcb the tcp_pcb to manipulate&
&* @param prio new priority&
&* 设置连接的优先级&
&* @参数pcb:操作的tcp_pcb&
&* @参数prio:新的优先级&
tcp_setprio(struct tcp_pcb *pcb, u8_t prio) &
& pcb-&prio =//设置新的优先级 &
#if TCP_QUEUE_OOSEQ &
&* Returns a copy of the given TCP segment.&
&* The pbuf and data are not copied, only the pointers&
&* @param seg the old tcp_seg&
&* @return a copy of seg&
&* 返回一个传入TCP段的复制&
&* pbuf与数据不复制,只是个指针 &
&* @参数seg:旧的tcp_seg&
&* @返回段的复制&
struct tcp_seg * &
tcp_seg_copy(struct tcp_seg *seg) &
& struct tcp_seg * &
& cseg = memp_malloc(MEMP_TCP_SEG);//分配空间 &
& if (cseg == NULL) {//分配失败? &
& & return NULL;返回 &
& SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); //copy一个段 &
& pbuf_ref(cseg-&p);//增加pbuf的引用计数 &
#if LWIP_CALLBACK_API &
&* Default receive callback that is called if the user didn't register&
&* a recv callback for the pcb.&
&* 默认的接收回调函数,如果用户没有给pcb注册一个接收回调函数&
static err_t &
tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) &
& if (p != NULL) {//传入的pbuf为空? &
& & pbuf_free(p);//释放 &
& } else if (err == ERR_OK) { &
& & return tcp_close(pcb);//关闭tcp &
& return ERR_OK; &
#endif /* LWIP_CALLBACK_API */ &
&* Kills the oldest active connection that has lower priority than prio.&
&* @param prio minimum priority&
&* 杀掉旧的比传入优先级低的激活链接&
&* @参数 prio:最小的优先级&
static void &
tcp_kill_prio(u8_t prio) &
& struct tcp_pcb *pcb, * &
& mprio = TCP_PRIO_MAX;//TCP最大的优先级 &
& /* We kill the oldest active connection that has lower priority than prio. */ &
& /* 我们杀掉最旧的比传入优先级低的激活链接. */ &
& inactivity = 0; &
& inactive = NULL; &
& for(pcb = tcp_active_ pcb != NULL; pcb = pcb-&next) {//遍历激活列表 &
& & if (pcb-&prio &= prio && &
& & & &pcb-&prio &= mprio && &
& & & &(u32_t)(tcp_ticks - pcb-&tmr) &= inactivity) {//对比优先级且看是否处在激活状态 &
& & & inactivity = tcp_ticks - pcb-&//计算静止时间 &
& & & inactive =//非激活 &
& & & mprio = pcb-&//获取优先级 &
& if (inactive != NULL) {//为空?非空则说明找到了 &
& & LWIP_DEBUGF(TCP_DEBUG, (&tcp_kill_prio: killing oldest PCB %p (%&S32_F&)\n&, &
& & & & & &(void *)inactive, inactivity)); &
& & tcp_abort(inactive);//终止它 &
& } & & & &
&* Kills the oldest connection that is in TIME_WAIT state.&
&* Called from tcp_alloc() if no more connections are available.&
&* 杀掉最久的在TIME_WAIT状态的连接.&
&* 如果没有更多连接可用则调用tcp_alloc.&
static void &
tcp_kill_timewait(void) &
& struct tcp_pcb *pcb, * &
& inactivity = 0; &
& inactive = NULL; &
& /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */ &
& /* 遍历TIME_WAIT状态的pcb列表,得到最旧的pcb. */ &
& for(pcb = tcp_tw_ pcb != NULL; pcb = pcb-&next) { &
& & if ((u32_t)(tcp_ticks - pcb-&tmr) &= inactivity) {//是否在静止状态?否 &
& & & inactivity = tcp_ticks - pcb-&//得到静止计时 &
& & & inactive =//静止指针指向pcb &
& if (inactive != NULL) {//找到了? &
& & LWIP_DEBUGF(TCP_DEBUG, (&tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%&S32_F&)\n&, &
& & & & & &(void *)inactive, inactivity)); &
& & tcp_abort(inactive);//终止 &
& } & & & &
&* Allocate a new tcp_pcb structure.&
&* @param prio priority for the new pcb&
&* @return a new tcp_pcb that initially is in state CLOSED&
&* 分配一个新的tcp_pcb结构.&
&* @参数prio:新pcb的优先级&
&* @返回一个新的初始化在CLOSED状态的tcp_pcb&
struct tcp_pcb * &
tcp_alloc(u8_t prio) &
& struct tcp_pcb * &
& pcb = memp_malloc(MEMP_TCP_PCB);//分配一个MEMP_TCP_PCB &
& if (pcb == NULL) {//分配成功? &
& & /* Try killing oldest connection in TIME-WAIT. */ &
& & /* 尝试杀掉一个在TIME-WAIT状态下最旧的连接. */ &
& & LWIP_DEBUGF(TCP_DEBUG, (&tcp_alloc: killing off oldest TIME-WAIT connection\n&)); &
& & tcp_kill_timewait(); &
& & /* Try to allocate a tcp_pcb again. */ &
& & /* 尝试再次分配一个tcp_pcb. */ &
& & pcb = memp_malloc(MEMP_TCP_PCB); &
& & if (pcb == NULL) { &
& & & /* Try killing active connections with lower priority than the new one. */ &
& & & /* 尝试杀掉比新块低优先级的激活的连接. */ &
& & & tcp_kill_prio(prio); &
& & & /* Try to allocate a tcp_pcb again. */ &
& & & /* 再次尝试分配pcb. */ &
& & & pcb = memp_malloc(MEMP_TCP_PCB); &
& if (pcb != NULL) { &
& & memset(pcb, 0, sizeof(struct tcp_pcb));//初始化内存置0 &
& & pcb-&prio = TCP_PRIO_NORMAL;//设置为普通优先级 &
& & pcb-&snd_buf = TCP_SND_BUF;//设置TCP发送的空间为256 &
& & pcb-&snd_queuelen = 0;//发送队列长度置0 &
& & pcb-&rcv_wnd = TCP_WND;//TCP结构窗口 &
& & pcb-&rcv_ann_wnd = TCP_WND;//TCP发布窗口 &
& & pcb-&tos = 0;//服务类型 &
& & pcb-&ttl = TCP_TTL;//默认存活时间 &
& & /* As initial send MSS, we use TCP_MSS but limit it to 536.&
& & & &The send MSS is updated when an MSS option is received. */ &
& & /* 作为初始化发送的MSS,我们用TCP_MSS但是最大限制在536.&
& & & &当一个MSS选项被接收,发送的MSS会被更新 & & & &
& & pcb-&mss = (TCP_MSS & 536) ? 536 : TCP_MSS;//设置pcb的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 =//最后的窗口更新序列和应答号 &
& & pcb-&snd_nxt =//下一个发送的心的序列号 &
& & pcb-&lastack =//最后的应答号 &
& & pcb-&snd_lbb =//下一个字节的进入buffer的序列数 & &&
& & pcb-&tmr = tcp_//计时器 &
& & pcb-&polltmr = 0;//池计时器 &
#if LWIP_CALLBACK_API &
& & pcb-&recv = tcp_recv_//接收函数默认 &
#endif /* LWIP_CALLBACK_API */ & &
& & /* Init KEEPALIVE timer */ &
& & /* 初始化KEEPALIVE计时器 */ &
& & pcb-&keep_idle &= TCP_KEEPIDLE_DEFAULT; &
#if LWIP_TCP_KEEPALIVE &
& & pcb-&keep_intvl = TCP_KEEPINTVL_DEFAULT;//初始化KEEPALIVE默认时间间隔 &
& & pcb-&keep_cnt & = TCP_KEEPCNT_DEFAULT;//初始化KEEPALIVE计数 &
#endif /* LWIP_TCP_KEEPALIVE */ &
& & pcb-&keep_cnt_sent = 0;//发送计数置0 &
&//返回新生成的pcb &
&* Creates a new TCP protocol control block but doesn't place it on&
&* any of the TCP PCB lists.&
&* The pcb is not put on any list until binding using tcp_bind().&
&* @internal: Maybe there should be a idle TCP PCB list where these&
&* PCBs are put on. Port reservation using tcp_bind() is implemented but&
&* allocated pcbs that are not bound can't be killed automatically if wanting&
&* to allocate a pcb with higher prio (@see tcp_kill_prio())&
&* @return a new tcp_pcb that initially is in state CLOSED&
&* &生成新的TCP PCB但没有房子到任何TCP PCB的列表&
&* &pcb没有放入任何列表直到使用tcp_bind绑定后&
&* @内部: 可能应该是一个闲置的TCP PCB列表哪里有PCB在里面&
&* 使用tcp_bind() 实现端口预定但是分配pcb没有绑定不能自动杀掉,&
&* &如果想分配一个pcb用更高的优先级(请看tcp_kill_prio())&
&* @返回一个新的初始化在CLOSED状态的tcp_pcb&
struct tcp_pcb * &
tcp_new(void) &
& return tcp_alloc(TCP_PRIO_NORMAL);//分配一个新的pcb &
&* Used to specify the argument that should be passed callback&
&* functions.&
&* @param pcb tcp_pcb to set the callback argument&
&* @param arg void pointer argument to pass to callback functions&
&* &使用指定参数,这个参数应该被传到回调函数去&
&* @参数pcb: tcp_pcb设置的回调函数参数&
&* @参数arg:一个void指针参数传到回调函数&
tcp_arg(struct tcp_pcb *pcb, void *arg) &
& pcb-&callback_arg =//设置回调函数参数 &
#if LWIP_CALLBACK_API &
&* Used to specify the function that should be called when a TCP&
&* connection receives data.&
&* @param pcb tcp_pcb to set the recv callback&
&* @param recv callback function to call for this pcb when data is received&
&* 使用指定的函数,当一个TCP连接收到数据是这个函数应该被调用&
&* @参数pcb: 设置接收回调函数的tcp_pcb&
&* @参数recv:当数据被接收了回调函数将为相应的pcb调用&
tcp_recv(struct tcp_pcb *pcb, &
& &err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)) &
& pcb-&recv =//设置相应的接收回调函数 &
&* Used to specify the function that should be called when TCP data&
&* has been successfully delivered to the remote host.&
&* @param pcb tcp_pcb to set the sent callback&
&* @param sent callback function to call for this pcb when data is successfully sent&
&* &使用指定的函数,当TCP数据已经成功传送到远程主机,这个函数应该被调用&
&* @参数pcb: 设置发送回调函数的tcp_pcb&
&* @参数send: 当数据已经成功送达,send回调函数将被调用&
tcp_sent(struct tcp_pcb *pcb, &
& &err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len)) &
& pcb-&sent =//设置相应的发送回调函数 &
&* Used to specify the function that should be called when a fatal error&
&* has occured on the connection.&
&* @param pcb tcp_pcb to set the err callback&
&* @param errf callback function to call for this pcb when a fatal error&
&* & & & &has occured on the connection&
&* &使用指定的函数,当一个致命错误发生在连接的时候,这个函数应该被调用&
&* @参数pcb: 设置错误的回调函数的tcp_pcb&
&* @参数errf: 但一个致命错误发生在连接的时候,errf回调函数将被调用 &
tcp_err(struct tcp_pcb *pcb, &
& &void (* errf)(void *arg, err_t err)) &
& pcb-&errf =//设置致命错误回调函数 &
&* Used for specifying the function that should be called when a&
&* LISTENing connection has been connected to another host.&
&* @param pcb tcp_pcb to set the accept callback&
&* @param accept callback function to call for this pcb when LISTENing&
&* & & & &connection has been connected to another host&
&* 使用指定的函数,当一个监听中的连接已经连接到另外的主机上,这个函数应该被调用&
&* @参数pcb: 设置接受的回调函数的tcp_pcb&
&* @参数accept: 当监听中的连接已经连接到其他的主机上,这个回调函数将被调用&
tcp_accept(struct tcp_pcb *pcb, &
& & &err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err)) &
& pcb-&accept =//设置接受回调函数 &
#endif /* LWIP_CALLBACK_API */ &
&* Used to specify the function that should be called periodically&
&* from TCP. The interval is specified in terms of the TCP coarse&
&* timer interval, which is called twice a second.&
&* 使用指定的函数,这个函数会定期的被TCP调用,时间间隔是指定在TCP粗糙的计时器间隔&
&* 这个函数每秒会被调用2次&
tcp_poll(struct tcp_pcb *pcb, &
& &err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval) &
#if LWIP_CALLBACK_API &
& pcb-&poll =//设置回调函数 &
#endif /* LWIP_CALLBACK_API */ & &
& pcb-&pollinterval =//设置时间间隔 &
&* Purges a TCP PCB. Removes any buffered data and frees the buffer memory&
&* (pcb-&ooseq, pcb-&unsent and pcb-&unacked are freed).&
&* @param pcb tcp_pcb to purge. The pcb itself is not deallocated!&
&* 清理一个TCP PCB,移除所有的buffer数据和释放buffer内存(pcb-&ooseq, pcb-&unsent和pcb-&unacked被释放 )&
&* @参数pcb:清理tcp_pcb.pcb自己不被释放!&
tcp_pcb_purge(struct tcp_pcb *pcb) &
& if (pcb-&state != CLOSED && &
& & &pcb-&state != TIME_WAIT && &
& & &pcb-&state != LISTEN) {//看状态都否CLOSED,TIME_WAIT,LISTEN? &
& & LWIP_DEBUGF(TCP_DEBUG, (&tcp_pcb_purge\n&)); &
#if TCP_LISTEN_BACKLOG &
& & if (pcb-&state == SYN_RCVD) {//状态是否为SYN_RCVD &
& & & /* Need to find the corresponding listen_pcb and decrease its accepts_pending */ &
& & & /* 需要找出相应的listen_pcb和减少它的接受等待*/ &
& & & struct tcp_pcb_listen * &
& & & LWIP_ASSERT(&tcp_pcb_purge: pcb-&state == SYN_RCVD but tcp_listen_pcbs is NULL&, &
& & & & tcp_listen_pcbs.listen_pcbs != NULL); &
& & & //遍历监听的pcb列表 &
& & & for (lpcb = tcp_listen_pcbs.listen_ lpcb != NULL; lpcb = lpcb-&next) { &
& & & & if ((lpcb-&local_port == pcb-&local_port) && &
& & & & & & (ip_addr_isany(&lpcb-&local_ip) || &
& & & & & & &ip_addr_cmp(&pcb-&local_ip, &lpcb-&local_ip))) { &
& & & & & & /* port and address of the listen pcb match the timed-out pcb */ &
& & & & & & /*监听pcb匹配超时的pcb端口和地址 */ &
& & & & & & LWIP_ASSERT(&tcp_pcb_purge: listen pcb does not have accepts pending&, &
& & & & & & & lpcb-&accepts_pending & 0); &
& & & & & & lpcb-&accepts_pending--;//接受挂起数减1 &
& & & & & & &
& & & & & } &
#endif /* TCP_LISTEN_BACKLOG */ &
& & if (pcb-&refused_data != NULL) {//拒绝数据为空? &
& & & LWIP_DEBUGF(TCP_DEBUG, (&tcp_pcb_purge: data left on -&refused_data\n&)); &
& & & pbuf_free(pcb-&refused_data);//释放拒绝数据 &
& & & pcb-&refused_data = NULL;//把指针指向空 &
& & if (pcb-&unsent != NULL) {//未发送全部数据 &
& & & LWIP_DEBUGF(TCP_DEBUG, (&tcp_pcb_purge: not all data sent\n&)); &
& & if (pcb-&unacked != NULL) {//未应答? &
& & & LWIP_DEBUGF(TCP_DEBUG, (&tcp_pcb_purge: data left on -&unacked\n&)); &
#if TCP_QUEUE_OOSEQ /* LW */ &
& & if (pcb-&ooseq != NULL) {//接收超出队列段序列 &
& & & LWIP_DEBUGF(TCP_DEBUG, (&tcp_pcb_purge: data left on -&ooseq\n&)); &
& & /* Stop the retransmission timer as it will expect data on unacked&
& & & &queue if it fires */ &
& & /* 停在重发计时器作为它将期待数据在为应答队列如果???*/ &
& & pcb-&rtime = -1; &
& & tcp_segs_free(pcb-&ooseq);//释放接收超出队列段 &
& & pcb-&ooseq = NULL; &
#endif /* TCP_QUEUE_OOSEQ */ &
& & tcp_segs_free(pcb-&unsent);//释放未发送段 &
& & tcp_segs_free(pcb-&unacked);//释放为应答段 &
& & pcb-&unacked = pcb-&unsent = NULL;//置空 &
&* Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.&
&* @param pcblist PCB list to purge.&
&* @param pcb tcp_pcb to purge. The pcb itself is also deallocated!&
&* &清理PCB和吧pcb冲列表中移除.所有延迟的应答被首先发送&
&* @参数pcblist:要清楚的PCB列表.&
&* @参数pcb:要清理的tcp_pcb. pcb自己也释放!&
tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) &
& TCP_RMV(pcblist, pcb);//移除pcb &
& tcp_pcb_purge(pcb);//清理pcb &
& /* if there is an outstanding delayed ACKs, send it */ &
& /* 如果有一个味解决的延迟应答,则发送*/ &
& if (pcb-&state != TIME_WAIT && &
& & &pcb-&state != LISTEN && &
& & &pcb-&flags & TF_ACK_DELAY) { &
& & pcb-&flags |= TF_ACK_NOW;//标记为应答 &
& & tcp_output(pcb);//发送 &
& if (pcb-&state != LISTEN) {//如果不是监听状态 &
& & LWIP_ASSERT(&unsent segments leaking&, pcb-&unsent == NULL); &
& & LWIP_ASSERT(&unacked segments leaking&, pcb-&unacked == NULL); &
#if TCP_QUEUE_OOSEQ &
& & LWIP_ASSERT(&ooseq segments leaking&, pcb-&ooseq == NULL); &
#endif /* TCP_QUEUE_OOSEQ */ &
& pcb-&state = CLOSED;//pcb状态设为CLOSED &
& LWIP_ASSERT(&tcp_pcb_remove: tcp_pcbs_sane()&, tcp_pcbs_sane()); &
&* Calculates a new initial sequence number for new connections.&
&* @return u32_t pseudo random sequence number&
&* 给新连接计算新的初始化队列好.&
&* @返回一个冒充的32位随机队列号&
tcp_next_iss(void) &
& static u32_t iss = 6510; &
& iss += tcp_ & & & /* XXX *//*初始化随机设定的大于6510的一个序列号*/ &
#if TCP_CALCULATE_EFF_SEND_MSS &
&* Calcluates the effective send mss that can be used for a specific IP address&
&* by using ip_route to determin the netif used to send to the address and&
&* calculating the minimum of TCP_MSS and that netif's mtu (if set).&
&* &计算有效的发送最大段大小,这样可以用来作为一个指定的IP地址&
& &通过使用ip_route来确定netif用来发送给的地址&
& &而且计算最小的TCP_MSS和这个netif的mtu(如果设置了)&
tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr) &
& u16_t mss_s; &
& struct netif * &
& outif = ip_route(addr);//从适当的网络接口中找到匹配的netif &
& if ((outif != NULL) && (outif-&mtu != 0)) {//outif找到?最大的传送单元为0? &
& & mss_s = outif-&mtu - IP_HLEN - TCP_HLEN;//最大传送单元减去IP头和TCP头 &
& & /* RFC 1122, chap 4.2.2.6:&
& & &* Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize&
& & &* We correct for TCP options in tcp_enqueue(), and don't support&
& & &* IP options&
& & /* RFC .2.6章:&
& & &* 有效的发送最大段大小 = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize&
& & &* 我们TCP选项在tcp_enqueue()是正确的,且没有支持IP选项&
& & sendmss = LWIP_MIN(sendmss, mss_s);//最小的发送段大小 &
&//得到有效的段大小 &&
#endif /* TCP_CALCULATE_EFF_SEND_MSS */ &
#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG &
&* Print a tcp header for debugging purposes.&
&* @param tcphdr pointer to a struct tcp_hdr&
&* 为调试目的打印tcp头.&
&* @参数tcphdr:结构体tcp_hdr的指针&
tcp_debug_print(struct tcp_hdr *tcphdr) &
& LWIP_DEBUGF(TCP_DEBUG, (&TCP header:\n&)); &
& LWIP_DEBUGF(TCP_DEBUG, (&+-------------------------------+\n&)); &
& LWIP_DEBUGF(TCP_DEBUG, (&| & &%5&U16_F& & & &| & &%5&U16_F& & & &| (src port, dest port)\n&, &
& & & & &ntohs(tcphdr-&src), ntohs(tcphdr-&dest))); &
& LWIP_DEBUGF(TCP_DEBUG, (&+-------------------------------+\n&)); &
& LWIP_DEBUGF(TCP_DEBUG, (&| & & & & & %010&U32_F& & & & & &| (seq no)\n&, &
& & & & & ntohl(tcphdr-&seqno))); &
& LWIP_DEBUGF(TCP_DEBUG, (&+-------------------------------+\n&)); &
& LWIP_DEBUGF(TCP_DEBUG, (&| & & & & & %010&U32_F& & & & & &| (ack no)\n&, &
& & & & &ntohl(tcphdr-&ackno))); &
& LWIP_DEBUGF(TCP_DEBUG, (&+-------------------------------+\n&)); &
& LWIP_DEBUGF(TCP_DEBUG, (&| %2&U16_F& | & |%&U16_F&%&U16_F&%&U16_F&%&U16_F&%&U16_F&%&U16_F&| & & %5&U16_F& & & | (hdrlen, flags (&, &
& & & &TCPH_HDRLEN(tcphdr), &
& & & & &TCPH_FLAGS(tcphdr) && 5 & 1, &
& & & & &TCPH_FLAGS(tcphdr) && 4 & 1, &
& & & & &TCPH_FLAGS(tcphdr) && 3 & 1, &
& & & & &TCPH_FLAGS(tcphdr) && 2 & 1, &
& & & & &TCPH_FLAGS(tcphdr) && 1 & 1, &
& & & & &TCPH_FLAGS(tcphdr) & 1, &
& & & & &ntohs(tcphdr-&wnd))); &
& tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); &
& LWIP_DEBUGF(TCP_DEBUG, (&), win)\n&)); &
& LWIP_DEBUGF(TCP_DEBUG, (&+-------------------------------+\n&)); &
& LWIP_DEBUGF(TCP_DEBUG, (&| & &0x%04&X16_F& & & | & & %5&U16_F& & & | (chksum, urgp)\n&, &
& & & & &ntohs(tcphdr-&chksum), ntohs(tcphdr-&urgp))); &
& LWIP_DEBUGF(TCP_DEBUG, (&+-------------------------------+\n&)); &
&* Print a tcp state for debugging purposes.&
&* @param s enum tcp_state to print&
&*为调试目的打印tcp状态.&
&* @参数s: 打印枚举tcp_state &
tcp_debug_print_state(enum tcp_state s) &
& LWIP_DEBUGF(TCP_DEBUG, (&State: &)); &
& switch (s) { &
& case CLOSED: &
& & LWIP_DEBUGF(TCP_DEBUG, (&CLOSED\n&)); &
&case LISTEN: &
& &LWIP_DEBUGF(TCP_DEBUG, (&LISTEN\n&)); &
& case SYN_SENT: &
& & LWIP_DEBUGF(TCP_DEBUG, (&SYN_SENT\n&)); &
& case SYN_RCVD: &
& & LWIP_DEBUGF(TCP_DEBUG, (&SYN_RCVD\n&)); &
& case ESTABLISHED: &
& & LWIP_DEBUGF(TCP_DEBUG, (&ESTABLISHED\n&)); &
& case FIN_WAIT_1: &
& & LWIP_DEBUGF(TCP_DEBUG, (&FIN_WAIT_1\n&)); &
& case FIN_WAIT_2: &
& & LWIP_DEBUGF(TCP_DEBUG, (&FIN_WAIT_2\n&)); &
& case CLOSE_WAIT: &
& & LWIP_DEBUGF(TCP_DEBUG, (&CLOSE_WAIT\n&)); &
& case CLOSING: &
& & LWIP_DEBUGF(TCP_DEBUG, (&CLOSING\n&)); &
& case LAST_ACK: &
& & LWIP_DEBUGF(TCP_DEBUG, (&LAST_ACK\n&)); &
& case TIME_WAIT: &
& & LWIP_DEBUGF(TCP_DEBUG, (&TIME_WAIT\n&)); &
&* Print tcp flags for debugging purposes.&
&* @param flags tcp flags, all active flags are printed&
&* 为调试目的打印tcp标示.&
&* @参数flags:tcp标示,打印所以激活的标示&
tcp_debug_print_flags(u8_t flags) &
& if (flags & TCP_FIN) { &
& & LWIP_DEBUGF(TCP_DEBUG, (&FIN &)); &
& if (flags & TCP_SYN) { &
& & LWIP_DEBUGF(TCP_DEBUG, (&SYN &)); &
& if (flags & TCP_RST) { &
& & LWIP_DEBUGF(TCP_DEBUG, (&RST &)); &
& if (flags & TCP_PSH) { &
& & LWIP_DEBUGF(TCP_DEBUG, (&PSH &)); &
& if (flags & TCP_ACK) { &
& & LWIP_DEBUGF(TCP_DEBUG, (&ACK &)); &
& if (flags & TCP_URG) { &
& & LWIP_DEBUGF(TCP_DEBUG, (&URG &)); &
& if (flags & TCP_ECE) { &
& & LWIP_DEBUGF(TCP_DEBUG, (&ECE &)); &
& if (flags & TCP_CWR) { &
& & LWIP_DEBUGF(TCP_DEBUG, (&CWR &)); &
& LWIP_DEBUGF(TCP_DEBUG, (&\n&)); &
&* Print all tcp_pcbs in every list for debugging purposes.&
&* 为调试打印所有的tcp_pcb在每个列表里面.&
tcp_debug_print_pcbs(void) &
& struct tcp_pcb * &
& LWIP_DEBUGF(TCP_DEBUG, (&Active PCB states:\n&)); &
& for(pcb = tcp_active_ pcb != NULL; pcb = pcb-&next) { &
& & LWIP_DEBUGF(TCP_DEBUG, (&Local port %&U16_F&, foreign port %&U16_F& snd_nxt %&U32_F& rcv_nxt %&U32_F& &, &
& & & & & & & & & & & &pcb-&local_port, pcb-&remote_port, &
& & & & & & & & & & & &pcb-&snd_nxt, pcb-&rcv_nxt)); &
& & tcp_debug_print_state(pcb-&state); &
& LWIP_DEBUGF(TCP_DEBUG, (&Listen PCB states:\n&)); &
& for(pcb = (struct tcp_pcb *)tcp_listen_pcbs. pcb != NULL; pcb = pcb-&next) { &
& & LWIP_DEBUGF(TCP_DEBUG, (&Local port %&U16_F&, foreign port %&U16_F& snd_nxt %&U32_F& rcv_nxt %&U32_F& &, &
& & & & & & & & & & & &pcb-&local_port, pcb-&remote_port, &
& & & & & & & & & & & &pcb-&snd_nxt, pcb-&rcv_nxt)); &
& & tcp_debug_print_state(pcb-&state); &
& LWIP_DEBUGF(TCP_DEBUG, (&TIME-WAIT PCB states:\n&)); &
& for(pcb = tcp_tw_ pcb != NULL; pcb = pcb-&next) { &
& & LWIP_DEBUGF(TCP_DEBUG, (&Local port %&U16_F&, foreign port %&U16_F& snd_nxt %&U32_F& rcv_nxt %&U32_F& &, &
& & & & & & & & & & & &pcb-&local_port, pcb-&remote_port, &
& & & & & & & & & & & &pcb-&snd_nxt, pcb-&rcv_nxt)); &
& & tcp_debug_print_state(pcb-&state); &
&* Check state consistency of the tcp_pcb lists.&
&* 检测tcp_pcb列表状态兼容性.&
tcp_pcbs_sane(void) &
& struct tcp_pcb * &
& for(pcb = tcp_active_ pcb != NULL; pcb = pcb-&next) { &
& & LWIP_ASSERT(&tcp_pcbs_sane: active pcb-&state != CLOSED&, pcb-&state != CLOSED); &
& & LWIP_ASSERT(&tcp_pcbs_sane: active pcb-&state != LISTEN&, pcb-&state != LISTEN); &
& & LWIP_ASSERT(&tcp_pcbs_sane: active pcb-&state != TIME-WAIT&, pcb-&state != TIME_WAIT); &
& for(pcb = tcp_tw_ pcb != NULL; pcb = pcb-&next) { &
& & LWIP_ASSERT(&tcp_pcbs_sane: tw pcb-&state == TIME-WAIT&, pcb-&state == TIME_WAIT); &
& return 1; &
#endif /* TCP_DEBUG */ &
#endif /* LWIP_TCP */ &
暂无相关文章
相关搜索:
相关阅读:
相关频道:
&&&&&&&&&&&&&&&&
C++教程最近更新}

我要回帖

更多关于 捷信怎么分期付款 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信