作者wjyaries (aries)
看板Linux
標題[問題] Socket IO 不正常
時間Thu Sep 15 13:57:53 2011
小弟有個 socket 程式在收封包時會卡住的問題,想請問大家,
程式片段 ==>
01: FD_ZERO(&readList);
02: FD_SET(udpSd, &readList);
03:
04: rc = select(maxfd1, &readList, NULL, NULL, wait_time, 0);
05: if (rc > 0) {
06: if (FD_ISSET(udpSd, &readList))
07: {
08: cnt = recvfrom(udpSd, udpBuf, SZ_UDP_BUF, 0, &from_addr, &from_len);
09: if (cnt > 0) {
10: .....
11: }
12: }
13: ...
14: }
此片段是某個 thread 會執行到的一段程式碼。
在執行時會卡在第8行,無法從 recvfrom 回來。
雖然在第8行,給 recvfrom 的 flag 是 0,表示是 blocked 的 socket,
然透過第4行的 select() 叫用,
應該是不會讓 recvfrom 因收不到 data 而卡住才對。
請教大家,發生 recvfrom 卡住的狀況其可能原因為何呢 ?
----
ps: 試過第8行的 flag 指定為 nonblocked 的話,就不會卡住,
但小弟想追查為何會卡住。
----
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 220.132.160.138
→ bitlife:我看你有設timeout,把它改成NULL看看. 09/15 14:44
→ wjyaries:讀manual, 若 timeout 設為 NULL, 則 select() 可能會 09/15 15:10
→ wjyaries:無窮無盡的等下去.... 09/15 15:11
→ wjyaries:另一狀況,在執行時 select() 時會回傳 Errno = 9 的錯誤 09/15 15:12
→ wjyaries:errno=9(EBADF)代表非法的 socket 代號 09/15 15:13
→ wjyaries:但 udpSd 沒有被 close, shutdown 的情況下,怎麼會出現 09/15 15:13
→ wjyaries:EBADF 的錯誤呢? 真是不解啊 ! 09/15 15:13
→ bitlife:你是TCP還是UDP?有沒有bind? 09/15 15:17
推 FireLake:select()傳回EBADF, 有可能是在之前的 recvfrom() 有 09/15 15:21
→ FireLake:ECONNRESET, 檢查一下recvfrom()是否回傳錯誤 09/15 15:23
→ wjyaries:recvfrom 就卡住了,不會 return (設為 blocked 時) 09/16 11:40
→ FireLake:這處的recvfrom()是整個程式惟一讀取(或send) updSd 的地 09/16 11:44
→ FireLake:方嗎? 若不是的話, 檢查之前send或recv是否有錯誤 09/16 11:45
→ FireLake:若這段程式是在迴圈內, 檢查 cnt<=0 的情況 09/16 11:53
→ wjyaries:是迴圈裡唯一在處理這個 UDP socket 的地方 09/16 16:06
→ wjyaries:由於不會 return, 所以沒機會檢查 cnt<=0 ~><~ 09/16 16:06
→ FireLake:你好像弄錯意思了, 這是迴圈裡唯一在處理這個udpSd的地方 09/17 08:52
→ FireLake:但是不是總是第一次執行到此處的recvfrom()就被block呢? 09/17 08:52
→ FireLake:如果不是的話, 要檢查迴圈之前執行到這個recvfrom()是否 09/17 08:53
→ FireLake:有錯誤. 如果總是第一次就被block, 要先確認udpSd是真的 09/17 08:54
→ FireLake:正確的initialized, 是真的可以用的socket. 若是你確認後 09/17 08:55
→ FireLake:者的方式是把它改成nonblocked, 還是要檢查 recvfrom()是 09/17 08:55
→ FireLake:否有傳回錯誤, 有的話可以幫你找到問題所在 09/17 08:56
→ wjyaries:嗯,並不是第一次進 recvfrom 就卡住。 09/18 15:51
→ wjyaries:迴圈一直跑,好像在第4~5次時開始卡。一卡就無法往下跑了 09/18 15:52
→ wjyaries:所以 updSockId 原來是可以收封包的,不知什麼原因, 09/18 15:53
→ wjyaries:select 明明告訴我可以去收封包了,但 recvfrom 卻收不到 09/18 15:54
→ wjyaries:目前的現像是這樣。懷疑是不是有某 thread 誤把同數字的 09/18 15:54
→ wjyaries:socket 或 file descriptor 給 shutdown or close 了, 09/18 15:55
→ wjyaries:但追查,沒發現有↑上述現象。真是不解 ! 09/18 15:56
→ wjyaries:改成 nonblock 的方式叫 recvfrom, 觀察 errno,有兩個值 09/18 15:57
→ wjyaries:1是 EAGAIN (timeout), 2是 88 or 9 表示 sockid 有誤. 09/18 15:58
→ FireLake:若是在第4~5次才開始卡, 就要檢查前面每一次的recvfrom() 09/18 16:16
→ FireLake:時有沒有錯誤, 也就是檢查 cnt<=0 的情況 09/18 16:17
→ FireLake:還有不同的thread會有可能接收同一個updSd嗎? 有的話也會 09/18 16:24
→ FireLake:造成block的情形 (但不會造成select有EBADF) 09/18 16:25
→ wjyaries:一直查不到有另一個thread 誤讀誤關掉 udpSockId 的動作 09/19 10:09
→ wjyaries:對於 select() EBADF 及 recvfrom 卡住,仍然無解... 09/19 10:10
→ FireLake:出現EBADF和 recvfrom卡住時, 不一定是這方的程式誤關掉 09/20 14:25
→ FireLake:socket, 也有可能是遠端關掉此socket. 檢查 "每一次" 的 09/20 14:26
→ FireLake:select()和recvfrom() 有沒有錯誤, 尤其是在出現 EBADF 09/20 14:27
→ FireLake:和recvfrom卡住之前的那幾次select和recvfrom 09/20 14:27
→ wjyaries:出錯前,每一次 select 都是 return >0 or =0 09/20 17:53
→ FireLake:之前的recvfrom()呢? 09/21 10:13