记一次lwip中 遇到 pcb == pcb-next 的pcb死循环debug过程
生活随笔
收集整理的這篇文章主要介紹了
记一次lwip中 遇到 pcb == pcb-next 的pcb死循环debug过程
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
amoBBS 阿莫電子論壇
標(biāo)題:? 記一次lwip中 遇到 pcb == pcb->next 的pcb死循環(huán)debug過(guò)程? [打印本頁(yè)]作者:? kayatsl? ?? 時(shí)間:? 2013-10-11 17:44
標(biāo)題:? 記一次lwip中 遇到 pcb == pcb->next 的pcb死循環(huán)debug過(guò)程
本帖最后由 kayatsl 于 2013-10-11 17:50 編輯?
[attach]144489[/attach]
如圖中, 在tcp_slowtmr() 中, 歷遍 tcp_tw_pcbs 過(guò)程中, 其中一個(gè) pcb -> next 指向pcb自身
導(dǎo)致while循環(huán)永久死在這里跳不出去, 程序死機(jī)..? ???這種問(wèn)題, 雖然說(shuō)必然會(huì)發(fā)生, 但發(fā)生的時(shí)間隨機(jī)性很強(qiáng), 很難捕捉到什么時(shí)候一定會(huì)出現(xiàn), 所以這種bug很難解決
這種情況在國(guó)外論壇搜了下, 都是同一個(gè)回答: 當(dāng)跑os的時(shí)候,有多個(gè)線程同時(shí)爭(zhēng)搶就會(huì)導(dǎo)致這種問(wèn)題產(chǎn)生
但到底怎么產(chǎn)生的, 和如何避免, 沒有作詳細(xì)介紹,也沒有案例分析..
這現(xiàn)象以前也有遇到過(guò), 其實(shí)這種情況通過(guò)寫一個(gè)定時(shí)檢測(cè)是否有pcb指向自身 和加入看門狗, 也能保證程序不會(huì)一直死在這,但這次一個(gè)偶然的機(jī)會(huì),決定跟個(gè)所以然.
[attach]144490[/attach]
這次由于時(shí)間片之間程序運(yùn)行的先后順序不同, 會(huì)導(dǎo)致hardfault產(chǎn)生, hardfault沒有截圖, 系統(tǒng)是記錄到我讀取一個(gè)非法地址, 引致hardfault
從堆棧中跟蹤得知, hardfault前跑的函數(shù)是 memp_malloc 中 memp_tab[type] = memp->next 引起的, 而memp 自身被指向了一個(gè)非內(nèi)存地址, 再讀取 ->next 必然導(dǎo)致出錯(cuò)
藍(lán)色圈是我加入的條件斷點(diǎn), 來(lái)捕捉異常狀態(tài).
這里得知memp_tab[2] 中的地址指向出問(wèn)題了, 但這和 pcb的死循環(huán)有什么關(guān)系呢? 到這里還是看不出頭緒.. 思路斷了, 那就回去繼續(xù)跟蹤 pcb的問(wèn)題
[attach]144491[/attach]
既然已經(jīng)知道死循環(huán)的 pcb是屬于 tcp_tw_pcbs 鏈表里面的, 那就 ctrl+shift+f 把所有對(duì) tcp_tw_pcbs 有操作的地方都找出來(lái), 統(tǒng)統(tǒng)下條件斷點(diǎn)
看執(zhí)行到哪一句后會(huì)出現(xiàn)死循環(huán)的現(xiàn)象
程序果然乖乖的死在陷阱里面, 這樣看來(lái), 明顯是運(yùn)行了 tcp_reg 后才出現(xiàn)的現(xiàn)象, 但為什么運(yùn)行這個(gè)后會(huì)導(dǎo)致死循環(huán)呢? 沒什么頭緒? 那就跟另一條線索
[attach]144502[/attach]
跟蹤一下 memp_tab的情況,
圖中紅字部分已經(jīng)說(shuō)得差不多了,??這里給了我們一個(gè)很重要的線索, 就是 memp_tab[]->next 和 tcp_tw_pcbs -> local_ip 為什么會(huì)重疊了..
試圖跟著這個(gè)函數(shù)返回一下, 看看會(huì)有什么情況
[attach]144493[/attach]
沒錯(cuò), 這里又重新給這個(gè)pcb賦值了, 然后又重新遞回到上層做處理..
也就是說(shuō), 系統(tǒng)給我們分配了一個(gè) 正在使用的內(nèi)存區(qū)域, 來(lái)處理新的東西, 那必然會(huì)導(dǎo)致和舊的東西發(fā)生沖突.. 要驗(yàn)證這句話? 繼續(xù)下條件斷點(diǎn)
[attach]144494[/attach]
圖中可以看到, 進(jìn)來(lái)的pcb, 本來(lái)是屬于 active_pcbs 鏈表的, 剛從 active 鏈表中移除, 準(zhǔn)備放到 timewait鏈表里面去, 但此時(shí)發(fā)現(xiàn), 這個(gè)pcb的內(nèi)存空間,正是tw_pcbs的內(nèi)存空間
其實(shí) TCP_REG 很簡(jiǎn)單, 就是把指針指一下, 就注冊(cè)過(guò)去了,??但就是因?yàn)樘?jiǎn)單了, 沒有做任何判斷, 所以自己指回了自己也不知道.
其實(shí)到這里, 可以在這個(gè)定義里面寫個(gè)判斷, 遇到指向自己的就不進(jìn)行操作, 但這樣還是沒找到最原始導(dǎo)致的原因..??所以必須繼續(xù)跟蹤下去
[attach]144495[/attach]
再截一個(gè)圖, 就是 死循環(huán)的圖..??大家可以比較一下這幾個(gè)圖里面紅圈圈著的地址,??截圖順序是按照程序執(zhí)行順序來(lái)的
[attach]144496[/attach]
回想一下, malloc的時(shí)候, 分配到同一個(gè)地址空間, 那明顯就是上一次分配的時(shí)候, ->next指針又指回自己了, 驗(yàn)證這個(gè)猜想, 繼續(xù)下條件斷點(diǎn)..
果然不出所料, memp == memp->next , 而這個(gè)是分配的時(shí)候?qū)е碌倪€是釋放的時(shí)候?qū)е碌? 暫時(shí)還不確定,
但是這個(gè)出錯(cuò)的現(xiàn)場(chǎng), 可以在堆棧中繼續(xù)追溯是哪里調(diào)用的, 但這里還不是第一現(xiàn)場(chǎng), 為了還原第一現(xiàn)場(chǎng), 那就繼續(xù)跟著 callstack回去找
[attach]144497[/attach]
這圖中很有意思..??這里程序開始的時(shí)候, 我使用 tcp_new 創(chuàng)建一個(gè)pcb, 而 tcp_new 又調(diào)用 malloc 來(lái)取出一個(gè) pcb的內(nèi)存空間
而我在 tcp_abort 這里打了個(gè)斷點(diǎn), 按道理來(lái)說(shuō), 我還沒有 abort掉這個(gè)鏈接, 空間是不應(yīng)該被釋放掉的, 但奇怪的是 memp_tab[2] 中指向的地址,確實(shí)是我正在使用的地址
memp_tab[] 鏈表是空閑內(nèi)存的鏈表, 而這個(gè)內(nèi)存塊是我正在使用的, 怎么會(huì)出現(xiàn)在空閑鏈表中??
越來(lái)越接近真相了,??就是這塊內(nèi)存申請(qǐng)后, 在使用中, 意外被別人釋放了, 那罪灰禍?zhǔn)椎降资钦l(shuí)??
[attach]144508[/attach]
那就繼續(xù)下條件斷點(diǎn)去捕捉釋放前的現(xiàn)象,.?
圖中可以看到, memp_Free 地址是跟 memp_alloc一樣的 ..??這里的原因是,我鏈接很頻繁,一個(gè)pcb還沒完全關(guān)閉, 又建立另一個(gè)鏈接, 所以會(huì)導(dǎo)致剛剛free出來(lái)的一個(gè)塊, 馬上又被用來(lái)使用了
所以這兩個(gè)地址一樣并不驚訝, 驚訝的是, 同一個(gè)地址, 為什么會(huì)出現(xiàn)在 memp_tab[2] 中???
這明顯是 free完這個(gè)塊, 然后 malloc到來(lái)用, 但用的過(guò)程中, 還沒等我釋放, 就被別的地方釋放了, 所以導(dǎo)致這塊正在使用的內(nèi)存塊會(huì)跑到了空閑內(nèi)存塊中去..
可以斷定是free多了一次出問(wèn)題了, 就好辦了..
[attach]144499[/attach]
由上面的現(xiàn)象可以估計(jì) 是pcb的內(nèi)存空間剛剛分配到, 很短時(shí)間又被釋放了, 既然是這樣, 就在 memp_free中下條件斷點(diǎn)??當(dāng)現(xiàn)在free的,剛好是剛剛malloc出來(lái)的內(nèi)存塊就斷
因?yàn)檎G闆r下, free的肯定是舊的空間, 不可能剛剛malloc就被free掉的.??
等了一段時(shí)間, 中陷阱了..??其實(shí)看到這個(gè)現(xiàn)場(chǎng)沒什么作用, 本來(lái)就已經(jīng)猜到的事情,??而在這里下斷點(diǎn)的目的, 是要跟蹤, 到底是誰(shuí)把它釋放掉的.
看 call stack 就一目了然了..??繼續(xù)跟回去 tcp_input中
[attach]144500[/attach]
這時(shí)候清晰了.. 這個(gè)pcb收到了關(guān)閉請(qǐng)求, 然后關(guān)閉掉pcb鏈接, 順便把內(nèi)存區(qū)域也 free掉了..
好了, 看到這里,??其實(shí)大家往回讀就知道到底 pcb死循環(huán)是怎么引起的了...
我正在開啟一條到服務(wù)器的鏈接, 但在等待確定鏈接已經(jīng)保持的過(guò)程中, 意外被服務(wù)器關(guān)閉了, 而由于時(shí)間太短, 這時(shí)候, 我應(yīng)用程序認(rèn)為 服務(wù)器并沒有連接上, 然后把這個(gè)tcp的控制塊 abort掉
而 abort 的時(shí)候調(diào)用 free 內(nèi)存的函數(shù),??卻不知道這塊內(nèi)存其實(shí)已經(jīng)是free掉的了, 再free一次, 就會(huì)出現(xiàn) memp_tab中 元素的 -next 指回自身.
而這時(shí)候再 malloc一個(gè)新內(nèi)存空間的時(shí)候, 由于 next永遠(yuǎn)是指回同一塊內(nèi)存區(qū)域, 所以導(dǎo)致下次再分配的時(shí)候, 還是分配同一塊空間給應(yīng)用層
但應(yīng)用層不知道分配的是同一塊空間, 而繼續(xù)使用, 然后就導(dǎo)致兩條鏈接共用同一個(gè)內(nèi)存區(qū)域.. 但lwip自己并不知道.
當(dāng)兩條鏈接最終注冊(cè)入同一個(gè) pcbs鏈表去管理的時(shí)候, 就會(huì)導(dǎo)致自己指回自己, 因?yàn)楸緛?lái)就是同一塊內(nèi)存,.. 最后就 pcb死循環(huán)了..
跟蹤到此結(jié)束
跟蹤完當(dāng)然是解決問(wèn)題了..
[attach]144503[/attach]
在 memp_free中 ,free之前做一個(gè)判斷 由于type == 2 屬于 tcp_pcb, 而 tcp_pcb 的 前四個(gè)字節(jié)是不可能為0x00的,?
所以可以判斷為當(dāng) memp->next 為 NULL 的時(shí)候, 這片內(nèi)存已經(jīng)釋放過(guò)了, 就不再重新釋放, 直接跳到程序末尾, 解鎖
經(jīng)驗(yàn)證, 方法正常, 因?yàn)?出問(wèn)題通常是 tcp_pcb 的問(wèn)題,因?yàn)?tcp控制太復(fù)雜了, 所以目前只控制 type==2 的地方就可以保證程序正常了.
到此 結(jié)貼.
作者:? kayatsl? ?? 時(shí)間:? 2013-10-11 18:04
大家有什么好方法避免的..??提一下.. 集思廣益啊...
作者:? 圣騎士by? ?? 時(shí)間:? 2013-10-11 18:06
我僅頂一下 表示我看不懂……
作者:? kayatsl? ?? 時(shí)間:? 2013-10-11 19:21
因?yàn)閮?nèi)存空間是直接分配出來(lái)的..??所以最后解決只能這么判斷
不過(guò)呵..
/* No sanity checks
* We don't need to preserve the struct memp while not allocated, so we
* can save a little space and set MEMP_SIZE to 0.
*/
#define MEMP_SIZE? ?? ?? ???0
這個(gè)memp_sizze 其實(shí)可以定義一下, 這里定義了4的話 , 每個(gè)頭部都會(huì)有4個(gè)空余字節(jié).
然后每次 在malloc中 memp = (struct memp*)((u8_t*)memp + MEMP_SIZE); 之前, 都先 memp->next = 賦一個(gè)固定的值;
然后 free的時(shí)候, 檢查下 ->next 指針 如果不是這個(gè)固定值的話, 就說(shuō)明已經(jīng)被free過(guò)了, 如果還是固定值的話, 就free一下..
理論上想了下, 應(yīng)該可以這么做, 只是每個(gè)區(qū)間都再加4個(gè)字節(jié)的話.. 這片內(nèi)存區(qū)域耗用還是挺龐大的..
作者:? kayatsl? ?? 時(shí)間:? 2013-10-11 19:28
網(wǎng)上都說(shuō) 多線程訪問(wèn)導(dǎo)致的, 而這次的情況, 確實(shí)也是因?yàn)閮蓷l線程都對(duì)一個(gè)對(duì)象訪問(wèn)導(dǎo)致的..
但由于我調(diào)用的是 rawapi , 所以在connect的時(shí)候, 必須vtaskdelay 將cpu控制權(quán)讓出來(lái)給 lwip內(nèi)核來(lái)跑, 才能connect上服務(wù)器
這個(gè)等待時(shí)間很難斷定 , 網(wǎng)速無(wú)法保證, 而就在等待過(guò)程中, 剛連上服務(wù)器,又被服務(wù)器踢掉, 踢掉的時(shí)候, 是用lwip的內(nèi)核線程來(lái)處理的.
所以...不從內(nèi)存分配的方向去解決的話, 這問(wèn)題基本是無(wú)解了...
希望給遇到同樣問(wèn)題的人, 看到之后, 能快速定位到自己程序哪里引起這問(wèn)題吧..
先寫到這了...
作者:? zf8848? ?? 時(shí)間:? 2013-10-11 21:25
感謝樓主共享自己的經(jīng)驗(yàn), lwip 確實(shí)有一些莫名奇妙的 bug.
作者:? fengyunyu? ?? 時(shí)間:? 2013-10-11 21:57
這個(gè)分析很到位啊。前面有個(gè)帖子似乎也提到了同樣的問(wèn)題。
作者:? yiyu? ?? 時(shí)間:? 2013-10-11 21:57
本帖最后由 yiyu 于 2013-10-11 22:09 編輯?
lwip是單線程的,所有api都是通過(guò)隊(duì)列通訊的,使用row是在裸奔情況下,應(yīng)用和lwip在一個(gè)線程內(nèi),
作者:? fengyunyu? ?? 時(shí)間:? 2013-10-11 22:04
yiyu 發(fā)表于 2013-10-11 21:57?
lwip是單線程的,所有api都是通過(guò)隊(duì)列通訊的,
lwip是單線程,如何理解?是不能用在使用操作系統(tǒng)的多任務(wù)的環(huán)境中?還是指?
作者:? yiyu? ?? 時(shí)間:? 2013-10-11 22:17
本帖最后由 yiyu 于 2013-10-11 23:19 編輯?
lwip在os中作為一個(gè)獨(dú)立線程實(shí)現(xiàn),外部應(yīng)用只能使用api調(diào)用,可以看一下api的實(shí)現(xiàn),很多都是把row函數(shù)通過(guò)消息隊(duì)列發(fā)送到lwip線程調(diào)用
api投遞消息
err_t
tcpip_apimsg(struct api_msg *apimsg)
{
??struct tcpip_msg msg;
??
??if (mbox != SYS_MBOX_NULL) {
? ? msg.type = TCPIP_MSG_API;
? ? msg.msg.apimsg = apimsg;
? ? ?sys_mbox_post(mbox, &msg);
? ? sys_arch_sem_wait(apimsg->msg.conn->op_completed, 0);
? ? return ERR_OK;
??}
??return ERR_VAL;
}
lwip線程
static void
tcpip_thread(void *arg)
{
??struct tcpip_msg *msg;
??LWIP_UNUSED_ARG(arg);
#if IP_REASSEMBLY
??sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
#endif /* IP_REASSEMBLY */
#if LWIP_ARP
??sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
#endif /* LWIP_ARP */
#if LWIP_DHCP
??sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
??sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
??sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
??sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
#endif /* LWIP_IGMP */
#if LWIP_DNS
??sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
#endif /* LWIP_DNS */
??if (tcpip_init_done != NULL) {
? ? tcpip_init_done(tcpip_init_done_arg);
??}
??LOCK_TCPIP_CORE();
??while (1) {? ?? ?? ?? ?? ?? ?? ?? ???/* MAIN Loop */
? ?? sys_mbox_fetch(mbox, (void *)&msg);
? ? switch (msg->type) {
#if LWIP_NETCONN
? ? case TCPIP_MSG_API:
? ?? ?LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
? ?? ?msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
? ?? ?break;
#endif /* LWIP_NETCONN */
? ? case TCPIP_MSG_INPKT:
? ?? ?LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
#if LWIP_ARP
? ?? ?if (msg->msg.inp.netif->flags & NETIF_FLAG_ETHARP) {
? ?? ???ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
? ?? ?} else
#endif /* LWIP_ARP */
? ?? ?{ ip_input(msg->msg.inp.p, msg->msg.inp.netif);
? ?? ?}
? ?? ?memp_free(MEMP_TCPIP_MSG_INPKT, msg);
? ?? ?break;
#if LWIP_NETIF_API
? ? case TCPIP_MSG_NETIFAPI:
? ?? ?LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
? ?? ?msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
? ?? ?break;
#endif /* LWIP_NETIF_API */
? ? case TCPIP_MSG_CALLBACK:
? ?? ?LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
? ?? ?msg->msg.cb.f(msg->msg.cb.ctx);
? ?? ?memp_free(MEMP_TCPIP_MSG_API, msg);
? ?? ?break;
? ? case TCPIP_MSG_TIMEOUT:
? ?? ?LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
? ?? ?sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
? ?? ?memp_free(MEMP_TCPIP_MSG_API, msg);
? ?? ?break;
? ? case TCPIP_MSG_UNTIMEOUT:
? ?? ?LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
? ?? ?sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
? ?? ?memp_free(MEMP_TCPIP_MSG_API, msg);
? ?? ?break;
? ? default:
? ?? ?break;
? ? }
??}
}
作者:? kayatsl? ?? 時(shí)間:? 2013-10-11 23:19
如果是用 netconn 來(lái)做的話, 確實(shí)是通過(guò)調(diào)用 tcpip_apimsg 來(lái)傳遞信息
但也可以直接調(diào)用raw_api 和設(shè)置自己的回調(diào)函數(shù)來(lái)做處理? ?lwip本身也是提供 raw_api 來(lái)給應(yīng)用做更快速的處理的..??處理得到位就不會(huì)出現(xiàn)爭(zhēng)搶的現(xiàn)象了.
作者:? fengyunyu? ?? 時(shí)間:? 2013-10-12 11:05
kayatsl 發(fā)表于 2013-10-11 23:19?
如果是用 netconn 來(lái)做的話, 確實(shí)是通過(guò)調(diào)用 tcpip_apimsg 來(lái)傳遞信息
但也可以直接調(diào)用raw_api 和設(shè)置自 ...
lwip到底能否商用還值得商榷。附網(wǎng)上看到一篇文章。
成功實(shí)現(xiàn)了LWIP的keepalive功能
原來(lái)的lwip沒有啟動(dòng)keepalive功能,導(dǎo)致tcp客戶端工作不可靠,主要就是無(wú)法處理服務(wù)器的斷線、斷網(wǎng)、down機(jī)等異常。表現(xiàn)是服務(wù)器故障后,tcp客戶端總是等待無(wú)法返回,造成鎖死。
處理方法:
1,使用TCPkeepalive功能,定時(shí)探測(cè)連接的狀態(tài),當(dāng)發(fā)生掉線時(shí),自動(dòng)關(guān)閉連接,正常返回。
2,檢測(cè)網(wǎng)線狀態(tài)PHY寄存器中有標(biāo)準(zhǔn)位。(沒有上一種方法好。)
下面詳細(xì)介紹如何啟動(dòng)keepalive
1,打開keepalive的標(biāo)志使能。
2,修改keepalive各個(gè)計(jì)數(shù)值,主要是改小,方便測(cè)試。
3,在pcb中需要置位keepalive的一個(gè)選項(xiàng)。pcb->so_options |= SOF_KEEPALIVE;
4,修改pcb的一處bug,該bug可以通過(guò)給我匯款獲得。
啟動(dòng)了keepalive才是真正的tcp連接,用起來(lái)穩(wěn)定可靠,異常爽快。
by 天遠(yuǎn)易 發(fā)表于:2012/7/13 10:04:43?
作者:? kayatsl? ?? 時(shí)間:? 2013-10-12 11:33
fengyunyu 發(fā)表于 2013-10-12 11:05?
lwip到底能否商用還值得商榷。附網(wǎng)上看到一篇文章。
keepalive 只是一個(gè)心跳包的作用..
本身應(yīng)用層有設(shè)計(jì)心跳包機(jī)制, 就不需要底層再做了..
作者:? fengyunyu? ?? 時(shí)間:? 2013-10-12 11:35
kayatsl 發(fā)表于 2013-10-12 11:33?
keepalive 只是一個(gè)心跳包的作用..
本身應(yīng)用層有設(shè)計(jì)心跳包機(jī)制, 就不需要底層再做了..
原文中的“4,修改pcb的一處bug,該bug可以通過(guò)給我匯款獲得。"
作者:? kayatsl? ?? 時(shí)間:? 2013-10-12 13:58
fengyunyu 發(fā)表于 2013-10-12 11:35?
原文中的“4,修改pcb的一處bug,該bug可以通過(guò)給我匯款獲得。"
哈哈哈... 肯定不是這個(gè)bug... 嚴(yán)格來(lái)說(shuō) 這個(gè)bug并不屬于pcb自身的..
作者:? DOER? ?? 時(shí)間:? 2013-10-12 20:50
密切關(guān)注中......
作者:? SNOOKER? ?? 時(shí)間:? 2013-10-12 22:10
高級(jí)技術(shù)帖,頂起
作者:? farmerzhangdl? ?? 時(shí)間:? 2013-10-14 11:11
我最近出現(xiàn)了一個(gè)lwip的問(wèn)題,也是連接上的。。。還在查
作者:? farmerzhangdl? ?? 時(shí)間:? 2013-10-14 11:12
keepalive并不一定需要,網(wǎng)上那個(gè)說(shuō)開啟了keepalive才是真的tcp我認(rèn)為是錯(cuò)誤的,完全可以通過(guò)自定義心跳包解決
作者:? kayatsl? ?? 時(shí)間:? 2013-10-14 11:16
farmerzhangdl 發(fā)表于 2013-10-14 11:12?
keepalive并不一定需要,網(wǎng)上那個(gè)說(shuō)開啟了keepalive才是真的tcp我認(rèn)為是錯(cuò)誤的,完全可以通過(guò)自定義心跳包 ...
哎.. 現(xiàn)在還是會(huì)遇到 指向自己, 只不過(guò)導(dǎo)致的原因不是原來(lái)的地方, 跑到新的地方了.. 而且跑大半天甚至幾天才能觸發(fā)一次.. 更不好跟了
作者:? fengyunyu? ?? 時(shí)間:? 2013-10-14 11:53
本帖最后由 fengyunyu 于 2013-10-14 17:38 編輯?
kayatsl 發(fā)表于 2013-10-14 11:16?
哎.. 現(xiàn)在還是會(huì)遇到 指向自己, 只不過(guò)導(dǎo)致的原因不是原來(lái)的地方, 跑到新的地方了.. 而且跑大半天甚至幾 ...
LZ是做Server還是做Client?據(jù)說(shuō)做Server比較穩(wěn)定,做Client則問(wèn)題較多。
作者:? kayatsl? ?? 時(shí)間:? 2013-10-14 12:03
同時(shí)做 TCP的Client? ?UDP的Server 和 Client
作者:? kayatsl? ?? 時(shí)間:? 2013-10-14 12:04
fengyunyu 發(fā)表于 2013-10-14 11:53?
LZ是做Server還是做Client?據(jù)說(shuō)做Server比較穩(wěn)定,做Client則問(wèn)題較多。另外,裸奔似乎更穩(wěn)定些。公司有 ...
做Server比較穩(wěn)定,做Client則問(wèn)題較多
這個(gè)說(shuō)法我也看到過(guò)..??后來(lái)經(jīng)過(guò)一段時(shí)間后判斷是他不會(huì)用..
作者:? inurl? ?? 時(shí)間:? 2013-10-14 15:04
? ? npcb = tcp_alloc(pcb->prio);
作者:? inurl? ?? 時(shí)間:? 2013-10-14 15:05
? ? npcb = tcp_alloc(pcb->prio);??后面加個(gè) ? ? ? ? if(npcb == tcp_active_pcbs ){
? ? ? ? ? ? ? ? tcp_close(npcb)? ? ? ? ;
? ? ? ? ? ? ? ? return ERR_OK;
? ? ? ? }
作者:? inurl? ?? 時(shí)間:? 2013-10-14 15:05
判一下這個(gè)npcb 是不是在tcp_active_pcbs 里面
作者:? kayatsl? ?? 時(shí)間:? 2013-10-14 15:34
inurl 發(fā)表于 2013-10-14 15:05?
npcb = tcp_alloc(pcb->prio);??后面加個(gè) ? ? ? ? if(npcb == tcp_active_pcbs ){
? ? ? ? ? ? ? ? tcp_close(npcb)? ? ? ? ;
? ? ? ? ? ? ? ? retu ...
這個(gè)需要?dú)v遍一下 active的鏈表,??不一定就是第一個(gè)pcb
同時(shí), 不一定在 active鏈表, 也可能在 tw鏈表..
但是我感覺, 避免發(fā)生, 總比發(fā)生了之后解決要好..
得找到發(fā)生的原因
作者:? farmerzhangdl? ?? 時(shí)間:? 2013-10-14 23:00
我是好多設(shè)備只有一臺(tái)發(fā)生過(guò)這個(gè)問(wèn)題,但是沒有查到原因,加了個(gè)狗,但是狗也沒起作用。。。
作者:? a317606001? ?? 時(shí)間:? 2013-10-15 10:08
mark? ?? ?? ?? ?? ?
作者:? inurl? ?? 時(shí)間:? 2013-10-16 08:41
mark?
作者:? inurl? ?? 時(shí)間:? 2013-10-16 11:19
你先把hard_fault解決了吧, 應(yīng)該跟lwip沒關(guān)系, 除非是lwip主任務(wù)堆棧溢出或者是任務(wù)退出了
作者:? kayatsl? ?? 時(shí)間:? 2013-10-16 11:48
inurl 發(fā)表于 2013-10-16 11:19?
你先把hard_fault解決了吧, 應(yīng)該跟lwip沒關(guān)系, 除非是lwip主任務(wù)堆棧溢出或者是任務(wù)退出了??...
hardfault 就是因?yàn)閙emp指針指出了內(nèi)存區(qū)域..
解決hardfault就是解決lwip的問(wèn)題
作者:? fengyunyu? ?? 時(shí)間:? 2013-10-16 12:07
kayatsl 發(fā)表于 2013-10-16 11:48?
hardfault 就是因?yàn)閙emp指針指出了內(nèi)存區(qū)域..
解決hardfault就是解決lwip的問(wèn)題 ...
看來(lái)內(nèi)存管理的水很深。
作者:? inurl? ?? 時(shí)間:? 2013-10-16 19:06
我發(fā)現(xiàn)tcp_tw_pcbs在tcp_close或者tcp_abort的時(shí)候不會(huì)釋放, 只能等到tcp_alloc失敗的時(shí)候才去釋放
作者:? inurl? ?? 時(shí)間:? 2013-10-16 19:09
??我覺得有可能是一個(gè)代碼重入的問(wèn)題。
作者:? inurl? ?? 時(shí)間:? 2013-10-16 19:11
??我覺得有可能是一個(gè)代碼重入的問(wèn)題。導(dǎo)致了重復(fù)釋放
作者:? kayatsl? ?? 時(shí)間:? 2013-10-17 09:16
inurl 發(fā)表于 2013-10-16 19:06?
我發(fā)現(xiàn)tcp_tw_pcbs在tcp_close或者tcp_abort的時(shí)候不會(huì)釋放, 只能等到tcp_alloc失敗的時(shí)候才去釋放 ...
tcp_close 是要等待服務(wù)器回復(fù)才會(huì)釋放? ?abort 調(diào)用 abanden, 是馬上釋放的.
是不是重入問(wèn)題還需要跟蹤下, 現(xiàn)在這問(wèn)題比之前更加不定時(shí)了,, 之前起碼說(shuō)一個(gè)小時(shí)內(nèi)還能出錯(cuò), 現(xiàn)在幾天都沒死一次, 真還原不了現(xiàn)場(chǎng)
作者:? fengyunyu? ?? 時(shí)間:? 2013-10-17 09:24
kayatsl 發(fā)表于 2013-10-17 09:16?
tcp_close 是要等待服務(wù)器回復(fù)才會(huì)釋放? ?abort 調(diào)用 abanden, 是馬上釋放的.
是不是重入問(wèn)題還需要跟蹤 ...
說(shuō)lwip穩(wěn)定的,一般是做server。做client,LZ算是吃螃蟹的。
作者:? 菜包? ?? 時(shí)間:? 2013-10-17 09:37
LZ好有耐心啊,這么一步一步跟進(jìn)分析,收藏一下以后備用,我的LwIP沒用在OS下面,跑得很正常
作者:? kayatsl? ?? 時(shí)間:? 2013-10-17 09:56
fengyunyu 發(fā)表于 2013-10-17 09:24?
說(shuō)lwip穩(wěn)定的,一般是做server。做client,LZ算是吃螃蟹的。
應(yīng)該不會(huì)吧... 做Client的人也不少的其實(shí)..
其實(shí)做Server和做Client, 感覺做起來(lái)差別倒不是很大..
作者:? inurl? ?? 時(shí)間:? 2013-10-17 21:06
kayatsl 發(fā)表于 2013-10-17 09:16
tcp_close 是要等待服務(wù)器回復(fù)才會(huì)釋放? ?abort 調(diào)用 abanden, 是馬上釋放的.
是不是重入問(wèn)題還需要跟蹤 ...
abort只在tcp_malloc的時(shí)候調(diào)用。你狂點(diǎn)tcp連接試試
作者:? fengyunyu? ?? 時(shí)間:? 2013-10-17 21:29
inurl 發(fā)表于 2013-10-17 21:06?
abort只在tcp_malloc的時(shí)候調(diào)用。你狂點(diǎn)tcp連接試試
那就相當(dāng)于DoS攻擊了。LWIP不管是做server還是client,這種情況都會(huì)崩潰
作者:? kayatsl? ?? 時(shí)間:? 2013-10-18 00:46
inurl 發(fā)表于 2013-10-17 21:06?
abort只在tcp_malloc的時(shí)候調(diào)用。你狂點(diǎn)tcp連接試試
因?yàn)榈谝淮蝝alloc的時(shí)候找不到空的內(nèi)存塊的話, 會(huì)將一個(gè)現(xiàn)有但已經(jīng)關(guān)閉的pcb釋放掉來(lái)用, 釋放就調(diào)用abort了.
作者:? inurl? ?? 時(shí)間:? 2013-10-21 19:35
有啥發(fā)現(xiàn)沒?
作者:? inurl? ?? 時(shí)間:? 2013-10-21 19:36
inurl 發(fā)表于 2013-10-17 21:06
abort只在tcp_malloc的時(shí)候調(diào)用。你狂點(diǎn)tcp連接試試
不會(huì)的,限制tcp就不會(huì)崩潰
作者:? kayatsl? ?? 時(shí)間:? 2013-10-22 00:34
inurl 發(fā)表于 2013-10-21 19:35?
有啥發(fā)現(xiàn)沒?
這幾天在忙別的東西..??明天再寫個(gè)陷阱給他吧..
作者:? fengyunyu? ?? 時(shí)間:? 2013-10-22 08:55
inurl 發(fā)表于 2013-10-21 19:36?
不會(huì)的,限制tcp就不會(huì)崩潰
限制tcp,如何限制?
作者:? inurl? ?? 時(shí)間:? 2013-10-23 08:41
fengyunyu 發(fā)表于 2013-10-22 08:55?
限制tcp,如何限制?
計(jì)數(shù) and tcp_accept()拒絕
作者:? fengyunyu? ?? 時(shí)間:? 2013-10-28 01:06
LZ,有新進(jìn)展了么?
作者:? xilou? ?? 時(shí)間:? 2013-10-28 09:13
技術(shù)貼,mark一下。
作者:? kayatsl? ?? 時(shí)間:? 2013-10-28 09:17
fengyunyu 發(fā)表于 2013-10-28 01:06?
LZ,有新進(jìn)展了么?
哎.. 沒連調(diào)試器的機(jī)子久不久都出問(wèn)題.. 連著調(diào)試器的. 跑了一個(gè)星期都沒出問(wèn)題.. 郁悶...
偶爾有一次進(jìn)去了. 結(jié)果忘了開中斷, 截不到原始記錄
作者:? fengyunyu? ?? 時(shí)間:? 2013-10-30 20:00
kayatsl 發(fā)表于 2013-10-28 09:17?
哎.. 沒連調(diào)試器的機(jī)子久不久都出問(wèn)題.. 連著調(diào)試器的. 跑了一個(gè)星期都沒出問(wèn)題.. 郁悶...
偶爾有一次進(jìn) ...
估計(jì)不用操作系統(tǒng),裸奔能解決問(wèn)題。最近也碰到過(guò)類似問(wèn)題,最后改成RAW模式未再測(cè)試到問(wèn)題。
作者:? kayatsl? ?? 時(shí)間:? 2013-10-31 00:19
fengyunyu 發(fā)表于 2013-10-30 20:00?
估計(jì)不用操作系統(tǒng),裸奔能解決問(wèn)題。最近也碰到過(guò)類似問(wèn)題,最后改成RAW模式未再測(cè)試到問(wèn)題。 ...
整個(gè)系統(tǒng)都搭好了, 不能說(shuō)不用操作系統(tǒng)
前兩天找到解決方案了, 復(fù)現(xiàn)了兩三次, 能夠解決了.
再測(cè)試多幾天, 確定沒問(wèn)題就可以結(jié)貼了...
作者:? kayatsl? ?? 時(shí)間:? 2013-11-1 15:35
kayatsl 發(fā)表于 2013-10-31 00:19?
整個(gè)系統(tǒng)都搭好了, 不能說(shuō)不用操作系統(tǒng)
前兩天找到解決方案了, 復(fù)現(xiàn)了兩三次, 能夠解決了.
[attach]149398[/attach]
問(wèn)題解決方案如上..??至今測(cè)試正常..
作者:? kayatsl? ?? 時(shí)間:? 2013-11-1 15:39
fengyunyu 發(fā)表于 2013-10-30 20:00?
估計(jì)不用操作系統(tǒng),裸奔能解決問(wèn)題。最近也碰到過(guò)類似問(wèn)題,最后改成RAW模式未再測(cè)試到問(wèn)題。 ...
54樓 解決方案
作者:? kayatsl? ?? 時(shí)間:? 2013-11-1 15:40
inurl 發(fā)表于 2013-10-21 19:35?
有啥發(fā)現(xiàn)沒?
54樓 解決方案
作者:? hecong129? ?? 時(shí)間:? 2013-11-13 10:26
mark 一下? ?新人學(xué)習(xí)了
作者:? gotearcom? ?? 時(shí)間:? 2013-11-15 15:28
kayatsl 發(fā)表于 2013-11-1 15:35?
問(wèn)題解決方案如上..??至今測(cè)試正常..
正在做的項(xiàng)目也用到lwip協(xié)議棧,也遇到你貼中死機(jī)的問(wèn)題,能否發(fā)一下解決的相關(guān)代碼,非常感謝!
作者:? gotearcom? ?? 時(shí)間:? 2013-11-15 15:29
郵箱:? gotearcom@163.com
作者:? kinsno? ?? 時(shí)間:? 2013-11-15 16:23
kayatsl 發(fā)表于 2013-11-1 15:40?
54樓 解決方案
我頂。。。。。真不錯(cuò)啊。。。。你算是第一個(gè)把LWIP進(jìn)行商用了嗎,真正的用于產(chǎn)品上了的吧。
作者:? kayatsl? ?? 時(shí)間:? 2013-11-18 11:02
kinsno 發(fā)表于 2013-11-15 16:23?
我頂。。。。。真不錯(cuò)啊。。。。你算是第一個(gè)把LWIP進(jìn)行商用了嗎,真正的用于產(chǎn)品上了的吧。 ...
我肯定不是第一個(gè)..? ?很早就有人商用了其實(shí).. 只不過(guò)國(guó)內(nèi)拿出來(lái)開帖探討的不是很多...
作者:? kayatsl? ?? 時(shí)間:? 2013-11-18 11:06
gotearcom 發(fā)表于 2013-11-15 15:28?
正在做的項(xiàng)目也用到lwip協(xié)議棧,也遇到你貼中死機(jī)的問(wèn)題,能否發(fā)一下解決的相關(guān)代碼,非常感謝! ...
死機(jī)方式像, 不代表就是這種死法... 你得設(shè)陷阱跟蹤...
我改棧加入的代碼基本都貼出來(lái)了.. 其余代碼都是產(chǎn)品上的了, 需保密..
作者:? ljt80158015? ?? 時(shí)間:? 2013-11-18 16:11
學(xué)習(xí)了 !? ? 謝謝樓主!
作者:? kinsno? ?? 時(shí)間:? 2013-11-18 22:52
kayatsl 發(fā)表于 2013-11-18 11:02?
我肯定不是第一個(gè)..? ?很早就有人商用了其實(shí).. 只不過(guò)國(guó)內(nèi)拿出來(lái)開帖探討的不是很多... ...
你們的項(xiàng)目是做設(shè)備端的嗎?
我們最近也要上一從機(jī)設(shè)備端,LWIP源碼里需要改動(dòng)的多嗎?需要全部啃過(guò)去嗎?還是可以直接DEBUG仿到哪改哪!當(dāng)然改前,肯定要了解前生今世才可以改的啊。之所以這樣問(wèn),是因?yàn)榭羞^(guò)一次UCOS的代碼,就不愿意再肯其它代碼了,實(shí)在是太傷神了。
作者:? kayatsl? ?? 時(shí)間:? 2013-11-19 09:43
kinsno 發(fā)表于 2013-11-18 22:52?
你們的項(xiàng)目是做設(shè)備端的嗎?
我們最近也要上一從機(jī)設(shè)備端,LWIP源碼里需要改動(dòng)的多嗎?需要全部啃過(guò)去嗎 ...
是設(shè)備端..
其實(shí)很多問(wèn)題在國(guó)外論壇上一般能找到答案的..
只是這個(gè)問(wèn)題我搜了好久都沒找到問(wèn)題最根源的引起原因, 所以才寫個(gè)帖, 記錄一下跟蹤過(guò)程
基本上你遇到問(wèn)題,只要找準(zhǔn)問(wèn)題的關(guān)鍵字, 一搜就很多了.. 必要時(shí),有些國(guó)外論壇要出國(guó)加速才能打開那些頁(yè)面..
作者:? kinsno? ?? 時(shí)間:? 2013-11-19 09:47
kayatsl 發(fā)表于 2013-11-19 09:43?
是設(shè)備端..
其實(shí)很多問(wèn)題在國(guó)外論壇上一般能找到答案的..
3KS, 好久不番墻了.
作者:? jzhang123? ?? 時(shí)間:? 2013-12-13 09:35
樓主牛B!!!!
作者:? migrant? ?? 時(shí)間:? 2013-12-13 10:05
查錯(cuò)精神不錯(cuò),學(xué)習(xí)學(xué)習(xí)
作者:? migrant? ?? 時(shí)間:? 2013-12-13 10:15
你的err_handle應(yīng)該能收到這個(gè)錯(cuò)誤啊,怎么沒有處理?
作者:? yangzi8000? ?? 時(shí)間:? 2014-2-19 22:21
這個(gè)帖子 很高級(jí)
作者:? skyformat? ?? 時(shí)間:? 2014-2-21 21:45
這個(gè)難度很大啊謝謝樓主分享經(jīng)驗(yàn)之談
作者:? 右手戒指? ?? 時(shí)間:? 2014-3-10 14:35
表示講的比較詳細(xì)深入,值得學(xué)習(xí)
作者:? 有點(diǎn)囂張? ?? 時(shí)間:? 2014-3-20 15:28
根據(jù)樓主的分析是pcb被釋放了2次,而多出來(lái)的那一次釋放是因?yàn)閘z在應(yīng)用層調(diào)用abort導(dǎo)致了,那么為什么不在應(yīng)用層避免使用abort來(lái)解決這個(gè)問(wèn)題。而要在free函數(shù)中來(lái)避免呢?
作者:? kayatsl? ?? 時(shí)間:? 2014-3-20 19:56
有點(diǎn)囂張 發(fā)表于 2014-3-20 15:28
根據(jù)樓主的分析是pcb被釋放了2次,而多出來(lái)的那一次釋放是因?yàn)閘z在應(yīng)用層調(diào)用abort導(dǎo)致了,那么為什么不在 ...
確實(shí), 應(yīng)用層能解決這問(wèn)題
如果僅僅是個(gè)人項(xiàng)目的話, 完全可以在應(yīng)用層解決,
但如果是開放性項(xiàng)目, 不排除別人以后用你的棧也會(huì)出現(xiàn)同樣情況
從底層出發(fā)保證穩(wěn)定是絕對(duì)的穩(wěn)定可靠
就像stm32的編程, 出現(xiàn)任何意外地址讀取寫入, 直接給你拋個(gè)hardfault, 而不是等你盲匆匆地去找.
作者:? 有點(diǎn)囂張? ?? 時(shí)間:? 2014-3-23 18:09
kayatsl 發(fā)表于 2014-3-20 19:56
確實(shí), 應(yīng)用層能解決這問(wèn)題
如果僅僅是個(gè)人項(xiàng)目的話, 完全可以在應(yīng)用層解決,
第一種方案,判斷memp->next == NULL 不成功的原因應(yīng)該是,釋放了這個(gè)memp并不是把各個(gè)成員變量賦值為NULL,而是將這個(gè)memp放回到對(duì)應(yīng)的空閑鏈表中,第二次釋放的時(shí)候memp-> next的值應(yīng)該是memp_tab的地址,而不為NULL,所以還是會(huì)進(jìn)行第二次釋放。
第二種方案,預(yù)留了MEMP_SIZE,這種方案可行,但是也要保證flag的值與memp_tab的值不相等;
作者:? kayatsl? ?? 時(shí)間:? 2014-3-24 10:04
有點(diǎn)囂張 發(fā)表于 2014-3-23 18:09
第一種方案,判斷memp->next == NULL 不成功的原因應(yīng)該是,釋放了這個(gè)memp并不是把各個(gè)成員變量賦值為NUL ...
這分析對(duì),?
第二個(gè), 內(nèi)存地址范圍已知的, 所以只要flag隨便賦一個(gè)不挨邊的地址就可以了.
作者:? fengyunyu? ?? 時(shí)間:? 2014-4-3 16:15
本帖最后由 fengyunyu 于 2014-4-3 16:17 編輯?
今天,認(rèn)真看了lz的分析過(guò)程,貌似沒有說(shuō)出現(xiàn)問(wèn)題的原因,只是在底層加了些容錯(cuò)代碼。另請(qǐng)教lz,if (type == 2)中,2代表什么?還有就是,lz應(yīng)用層代碼是不是寫法有問(wèn)題,才導(dǎo)致出現(xiàn)該問(wèn)題?
作者:? kayatsl? ?? 時(shí)間:? 2014-4-3 17:28
fengyunyu 發(fā)表于 2014-4-3 16:15
今天,認(rèn)真看了lz的分析過(guò)程,貌似沒有說(shuō)出現(xiàn)問(wèn)題的原因,只是在底層加了些容錯(cuò)代碼。另請(qǐng)教lz,if (type = ...
原因總結(jié)就是一句話.??abort 被調(diào)用了2次. 一次是我調(diào)的, 一次是內(nèi)核調(diào)的
作者:? fengyunyu? ?? 時(shí)間:? 2014-4-3 20:20
kayatsl 發(fā)表于 2014-4-3 17:28
原因總結(jié)就是一句話.??abort 被調(diào)用了2次. 一次是我調(diào)的, 一次是內(nèi)核調(diào)的
要是內(nèi)核在進(jìn)行abort的時(shí)候,有一個(gè)回調(diào)函數(shù)通知應(yīng)用層就好了。
作者:? fengyunyu? ?? 時(shí)間:? 2014-4-30 15:13
http://www.amobbs.com/thread-4369748-1-1.html
”我移植的是裸機(jī)版的lwip,在程序跑的過(guò)程中發(fā)現(xiàn)有時(shí)候會(huì)產(chǎn)生死機(jī)的情況
檢查發(fā)現(xiàn)停在了類似下面的地方
此處是void tcp_fasttmr(void)中的一句代碼
/* send delayed ACKs */
for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next)
在這里tcp_active_pcbs和tcp_active_pcbs->next會(huì)出現(xiàn)相等的情況,然后for循環(huán)就回移植循環(huán)下去。抓狂中……
經(jīng)過(guò)測(cè)試可能和tcp連接建立和斷開有關(guān)系,但是找不到問(wèn)題的根源。請(qǐng)問(wèn)有誰(shuí)碰到過(guò)類似的情況?是怎么解決的呀。“
這個(gè)帖子中的問(wèn)題,LZ遇到過(guò)么?
作者:? fengyunyu? ?? 時(shí)間:? 2014-4-30 15:22
http://blog.csdn.net/hecong_kit/article/details/24415693
這里貌似有一個(gè)新的類似問(wèn)題的解決方案。
作者:? ywhbn? ?? 時(shí)間:? 2014-4-30 15:28
用兩句話總結(jié)下?
作者:? kayatsl? ?? 時(shí)間:? 2014-4-30 15:36
fengyunyu 發(fā)表于 2014-4-30 15:13
http://www.amobbs.com/thread-4369748-1-1.html
”我移植的是裸機(jī)版的lwip,在程序跑的過(guò)程中發(fā)現(xiàn)有時(shí)候 ...
lwip 里面有很多處 for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next)??的地方
void tcp_fasttmr(void) 只是其中一處
但不管死在哪處,??只要鏈表鏈回自身 基本都可以歸為同一個(gè)問(wèn)題.
你下面貼的那個(gè), 粗略看了下, 跟我這個(gè)問(wèn)題貌似關(guān)系不大
作者:? fengyunyu? ?? 時(shí)間:? 2014-4-30 16:21
kayatsl 發(fā)表于 2014-4-30 15:36
lwip 里面有很多處 for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next)??的地方
void tcp_fast ...
請(qǐng)問(wèn)54樓圖中memp_use_flag是自定義的一個(gè)常量么?另外,memp_free中,跳到Free_Already后,如何處理的,直接return么?
作者:? fengyunyu? ?? 時(shí)間:? 2014-4-30 17:12
另外,LZ把tcp_abort(clippcb)改成tcp_close(clippcb)估計(jì)就對(duì)了。
作者:? fengyunyu? ?? 時(shí)間:? 2014-5-1 01:05
http://blog.sina.com.cn/s/blog_5d18cf7f010100nj.html
這里貌似有一個(gè)正確的答案。
作者:? kayatsl? ?? 時(shí)間:? 2014-5-3 11:01
fengyunyu 發(fā)表于 2014-5-1 01:05
http://blog.sina.com.cn/s/blog_5d18cf7f010100nj.html
這里貌似有一個(gè)正確的答案。
你這個(gè)貼就是我為什么用 abort 而不用close的原因, 但不是我這個(gè)問(wèn)題的正解
作者:? fengyunyu? ?? 時(shí)間:? 2014-5-3 14:00
kayatsl 發(fā)表于 2014-5-3 11:01
你這個(gè)貼就是我為什么用 abort 而不用close的原因, 但不是我這個(gè)問(wèn)題的正解
可能,用close更合適些。close后,pcb的釋放是由lwip自己進(jìn)行。應(yīng)用層,重新進(jìn)行tcp_new應(yīng)該就行了。
作者:? kayatsl? ?? 時(shí)間:? 2014-5-4 09:23
close 和 abort 最大的區(qū)別是 close會(huì)發(fā)送關(guān)閉請(qǐng)求給對(duì)方, 然后等到對(duì)方關(guān)閉的ack后才會(huì)真正釋放掉pcb
但我的函數(shù)是用在連接的時(shí)候的, 連接還沒真正建立, 是不需要發(fā)送關(guān)閉請(qǐng)求的, 可以直接abort
作者:? kayatsl? ?? 時(shí)間:? 2014-5-4 09:23
fengyunyu 發(fā)表于 2014-5-3 14:00
可能,用close更合適些。close后,pcb的釋放是由lwip自己進(jìn)行。應(yīng)用層,重新進(jìn)行tcp_new應(yīng)該就行了。 ...
close 和 abort 最大的區(qū)別是 close會(huì)發(fā)送關(guān)閉請(qǐng)求給對(duì)方, 然后等到對(duì)方關(guān)閉的ack后才會(huì)真正釋放掉pcb
但我的函數(shù)是用在連接的時(shí)候的, 連接還沒真正建立, 是不需要發(fā)送關(guān)閉請(qǐng)求的, 可以直接abort
喔.. 忘了按回復(fù)來(lái)發(fā).. 重發(fā)一條吧...
作者:? fengyunyu? ?? 時(shí)間:? 2014-5-4 10:16
kayatsl 發(fā)表于 2014-5-4 09:23
close 和 abort 最大的區(qū)別是 close會(huì)發(fā)送關(guān)閉請(qǐng)求給對(duì)方, 然后等到對(duì)方關(guān)閉的ack后才會(huì)真正釋放掉pcb
...
直接用tcp_abort可能有些問(wèn)題,以下是tcp_abort()的部分代碼:
...
??if (pcb->state == TIME_WAIT) {
? ? tcp_pcb_remove(&tcp_tw_pcbs, pcb);
? ? memp_free(MEMP_TCP_PCB, pcb);
??} else {
? ? seqno = pcb->snd_nxt;
? ? ackno = pcb->rcv_nxt;
? ? ip_addr_copy(local_ip, pcb->local_ip);
? ? ip_addr_copy(remote_ip, pcb->remote_ip);
? ? local_port = pcb->local_port;
? ? remote_port = pcb->remote_port;
#if LWIP_CALLBACK_API
? ? errf = pcb->errf;
#endif /* LWIP_CALLBACK_API */
? ? errf_arg = pcb->callback_arg;
? ? tcp_pcb_remove(&tcp_active_pcbs, pcb);
? ? if (pcb->unacked != NULL) {
? ?? ?tcp_segs_free(pcb->unacked);
? ? }
? ? if (pcb->unsent != NULL) {
? ?? ?tcp_segs_free(pcb->unsent);
? ? }
#if TCP_QUEUE_OOSEQ? ??
? ? if (pcb->ooseq != NULL) {
? ?? ?tcp_segs_free(pcb->ooseq);
? ? }
#endif /* TCP_QUEUE_OOSEQ */
? ? memp_free(MEMP_TCP_PCB, pcb);
? ? TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
? ? if (reset) {
? ?? ?LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n"));
? ?? ?tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);
? ? }
代碼中的 tcp_pcb_remove(&tcp_active_pcbs, pcb);可能會(huì)出現(xiàn)問(wèn)題。
作者:? fengyunyu? ?? 時(shí)間:? 2014-5-4 10:19
kayatsl 發(fā)表于 2014-5-4 09:23
close 和 abort 最大的區(qū)別是 close會(huì)發(fā)送關(guān)閉請(qǐng)求給對(duì)方, 然后等到對(duì)方關(guān)閉的ack后才會(huì)真正釋放掉pcb
...
tcp_close則處理了連接還沒有真正建立的情況,tcp_close的部分代碼如下:
...
??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. */
? ? err = ERR_OK;
? ? if (pcb->local_port != 0) {
? ?? ?TCP_RMV(&tcp_bound_pcbs, pcb);
? ? }
? ? memp_free(MEMP_TCP_PCB, pcb);
? ? pcb = NULL;
? ? break;
其中TCP_RMV(&tcp_bound_pcbs, pcb)處理了連接還沒有真正建立的情況。
作者:? kayatsl? ?? 時(shí)間:? 2014-5-4 16:52
fengyunyu 發(fā)表于 2014-5-4 10:19
tcp_close則處理了連接還沒有真正建立的情況,tcp_close的部分代碼如下:
...
其實(shí)你是沒有搞懂我上面描述的問(wèn)題在哪.
其實(shí)問(wèn)題在于儲(chǔ)存pcb的地方, 系統(tǒng)自身釋放了一次, 而我不知道, 變量存在我身上, 而我又再釋放一次.. 所以就卡擦了..
這跟調(diào)哪個(gè)函數(shù)是沒關(guān)系的, 最終都是mempfree
作者:? fengyunyu? ?? 時(shí)間:? 2014-5-4 17:06
kayatsl 發(fā)表于 2014-5-4 16:52
其實(shí)你是沒有搞懂我上面描述的問(wèn)題在哪.
其實(shí)問(wèn)題在于儲(chǔ)存pcb的地方, 系統(tǒng)自身釋放了一次, 而我不知道,??...
你在mem_free中加了補(bǔ)丁,這個(gè)是看到了。我是覺得,你在應(yīng)用層對(duì)raw_api的使用“方法”可能有問(wèn)題,引起了這個(gè)“問(wèn)題”。
作者:? kayatsl? ?? 時(shí)間:? 2014-5-4 17:13
fengyunyu 發(fā)表于 2014-5-4 17:06
你在mem_free中加了補(bǔ)丁,這個(gè)是看到了。我是覺得,你在應(yīng)用層對(duì)raw_api的使用“方法”可能有問(wèn)題,引起 ...
上面回帖已經(jīng)說(shuō)了,??問(wèn)題就在于 "變量存在我身上"
而不是調(diào)了哪個(gè)函數(shù)
作者:? fengyunyu? ?? 時(shí)間:? 2014-5-5 11:06
貌似老外使用lwip 1.4.1,raw模式也碰到類似問(wèn)題。
以下轉(zhuǎn)自網(wǎng)絡(luò):
lwip tcp_tw_pcbs list problem in tcp_slowtmr()
I have been having a problem in the tcp_slowtmr() function in tcp.c.??I have been using the raw api for a quite a while to implement TCP servers listening on several different ports.??I have not really had any problems so far.??Recently I have also implemented TCP client connection which quickly open up a TCP client connection read/write some data and then close the connection.??This sequence repeats itself over and over connecting to several different remote TCP servers.??Things seem to work fairly well until I start introducing some error conditions like extending remote server resonse times or reducing my timeouts waiting for data to be received.??This causes my code to timeout and close the TCP connection (probably while some responses may come back in later).??I have also tried disconnecting some of my remote servers network connections so that the initial client connection attempts will fail.??I am just mainly trying to do some general stress testing with normal conditions that may occur when deploying the application.?
The problem that I am having occurs when adding these additional stress tests, and possibly with normal conditions after an extended period of time.??I have not nailed down the exact cause as of yet.??I finally get into a lock up condition when calling the tcp_slowtmr() function.??The lockup occurs cycling through the code lines highlighted below from the tcp_slowtmr() function:
??/* Steps through all of the TIME-WAIT PCBs. */
prev = NULL;
??pcb = tcp_tw_pcbs;
??while (pcb != NULL) {
? ? LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
? ? pcb_remove = 0;
? ? /* Check if this PCB has stayed long enough in TIME-WAIT */
? ? if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {
? ?? ?++pcb_remove;
? ? }
? ?
? ? /* If the PCB should be removed, do it. */
? ? if (pcb_remove) {
? ?? ?struct tcp_pcb *pcb2;
? ?? ?tcp_pcb_purge(pcb);
? ?? ?/* Remove PCB from tcp_tw_pcbs list. */
? ?? ?if (prev != NULL) {
? ?? ???LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);
? ?? ???prev->next = pcb->next;
? ?? ?} else {
? ?? ???/* This PCB was the first. */
? ?? ???LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);
? ?? ???tcp_tw_pcbs = pcb->next;
? ?? ?}
? ?? ?pcb2 = pcb;
? ?? ?pcb = pcb->next;
? ?? ?memp_free(MEMP_TCP_PCB, pcb2);
? ? } else {
? ?? ?prev = pcb;
? ?? ?pcb = pcb->next;
? ? }
??}
The problem occurs when the first item on the tcp_tw_pcbs list points back to itself:??pcb->next == pcb, so the code never exits the while loop.??The tcp_ticks value never changes in this part of the code so pcb_remove is never set > 0 either.
This is a single threaded application and only the standard interrupt handling function are being used.??This is an application running on an LPC4350 using the LPCOpen library from NXP with lwip v1.4.1.
It seems like the problem is created if I start calling tcp_close() to close my client connections.??If I use tcp_abort() instead then I don’t seem to have to problem – It does however cause undesirable sequences in wireshark.?
What is the recommended sequence to close a tcp client session using the raw api?
Any suggestions as to what I may be doing wrong here or could this possibly be a bug that has been seen before in lwip?
Thanks,
Greg Dunn
作者:? hxke? ?? 時(shí)間:? 2014-6-5 17:30
收藏,頂起。
作者:? jsszdfdn? ?? 時(shí)間:? 2014-9-17 21:45
樓主的分析實(shí)在精辟,佩服。
作者:? embeddev_1? ?? 時(shí)間:? 2014-9-22 20:59
mark!!!
作者:? xaper? ?? 時(shí)間:? 2014-9-22 21:17
好詳細(xì) ?
| 歡迎光臨 amoBBS 阿莫電子論壇 (https://www.amobbs.com/) | Powered by Discuz! X3.4 |
總結(jié)
以上是生活随笔為你收集整理的记一次lwip中 遇到 pcb == pcb-next 的pcb死循环debug过程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: lwip之数据收发流程_3
- 下一篇: FreeRTOS — 临界段和开关中断