[問題] Socket IO 不正常

看板Linux作者 (aries)時間14年前 (2011/09/15 13:57), 編輯推噓1(1043)
留言44則, 3人參與, 最新討論串1/1
小弟有個 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

09/15 14:44, , 1F
我看你有設timeout,把它改成NULL看看.
09/15 14:44, 1F

09/15 15:10, , 2F
讀manual, 若 timeout 設為 NULL, 則 select() 可能會
09/15 15:10, 2F

09/15 15:11, , 3F
無窮無盡的等下去....
09/15 15:11, 3F

09/15 15:12, , 4F
另一狀況,在執行時 select() 時會回傳 Errno = 9 的錯誤
09/15 15:12, 4F

09/15 15:13, , 5F
errno=9(EBADF)代表非法的 socket 代號
09/15 15:13, 5F

09/15 15:13, , 6F
但 udpSd 沒有被 close, shutdown 的情況下,怎麼會出現
09/15 15:13, 6F

09/15 15:13, , 7F
EBADF 的錯誤呢? 真是不解啊 !
09/15 15:13, 7F

09/15 15:17, , 8F
你是TCP還是UDP?有沒有bind?
09/15 15:17, 8F

09/15 15:21, , 9F
select()傳回EBADF, 有可能是在之前的 recvfrom() 有
09/15 15:21, 9F

09/15 15:23, , 10F
ECONNRESET, 檢查一下recvfrom()是否回傳錯誤
09/15 15:23, 10F

09/16 11:40, , 11F
recvfrom 就卡住了,不會 return (設為 blocked 時)
09/16 11:40, 11F

09/16 11:44, , 12F
這處的recvfrom()是整個程式惟一讀取(或send) updSd 的地
09/16 11:44, 12F

09/16 11:45, , 13F
方嗎? 若不是的話, 檢查之前send或recv是否有錯誤
09/16 11:45, 13F

09/16 11:53, , 14F
若這段程式是在迴圈內, 檢查 cnt<=0 的情況
09/16 11:53, 14F

09/16 16:06, , 15F
是迴圈裡唯一在處理這個 UDP socket 的地方
09/16 16:06, 15F

09/16 16:06, , 16F
由於不會 return, 所以沒機會檢查 cnt<=0 ~><~
09/16 16:06, 16F

09/17 08:52, , 17F
你好像弄錯意思了, 這是迴圈裡唯一在處理這個udpSd的地方
09/17 08:52, 17F

09/17 08:52, , 18F
但是不是總是第一次執行到此處的recvfrom()就被block呢?
09/17 08:52, 18F

09/17 08:53, , 19F
如果不是的話, 要檢查迴圈之前執行到這個recvfrom()是否
09/17 08:53, 19F

09/17 08:54, , 20F
有錯誤. 如果總是第一次就被block, 要先確認udpSd是真的
09/17 08:54, 20F

09/17 08:55, , 21F
正確的initialized, 是真的可以用的socket. 若是你確認後
09/17 08:55, 21F

09/17 08:55, , 22F
者的方式是把它改成nonblocked, 還是要檢查 recvfrom()是
09/17 08:55, 22F

09/17 08:56, , 23F
否有傳回錯誤, 有的話可以幫你找到問題所在
09/17 08:56, 23F

09/18 15:51, , 24F
嗯,並不是第一次進 recvfrom 就卡住。
09/18 15:51, 24F

09/18 15:52, , 25F
迴圈一直跑,好像在第4~5次時開始卡。一卡就無法往下跑了
09/18 15:52, 25F

09/18 15:53, , 26F
所以 updSockId 原來是可以收封包的,不知什麼原因,
09/18 15:53, 26F

09/18 15:54, , 27F
select 明明告訴我可以去收封包了,但 recvfrom 卻收不到
09/18 15:54, 27F

09/18 15:54, , 28F
目前的現像是這樣。懷疑是不是有某 thread 誤把同數字的
09/18 15:54, 28F

09/18 15:55, , 29F
socket 或 file descriptor 給 shutdown or close 了,
09/18 15:55, 29F

09/18 15:56, , 30F
但追查,沒發現有↑上述現象。真是不解 !
09/18 15:56, 30F

09/18 15:57, , 31F
改成 nonblock 的方式叫 recvfrom, 觀察 errno,有兩個值
09/18 15:57, 31F

09/18 15:58, , 32F
1是 EAGAIN (timeout), 2是 88 or 9 表示 sockid 有誤.
09/18 15:58, 32F

09/18 16:16, , 33F
若是在第4~5次才開始卡, 就要檢查前面每一次的recvfrom()
09/18 16:16, 33F

09/18 16:17, , 34F
時有沒有錯誤, 也就是檢查 cnt<=0 的情況
09/18 16:17, 34F

09/18 16:24, , 35F
還有不同的thread會有可能接收同一個updSd嗎? 有的話也會
09/18 16:24, 35F

09/18 16:25, , 36F
造成block的情形 (但不會造成select有EBADF)
09/18 16:25, 36F

09/19 10:09, , 37F
一直查不到有另一個thread 誤讀誤關掉 udpSockId 的動作
09/19 10:09, 37F

09/19 10:10, , 38F
對於 select() EBADF 及 recvfrom 卡住,仍然無解...
09/19 10:10, 38F

09/20 14:25, , 39F
出現EBADF和 recvfrom卡住時, 不一定是這方的程式誤關掉
09/20 14:25, 39F

09/20 14:26, , 40F
socket, 也有可能是遠端關掉此socket. 檢查 "每一次" 的
09/20 14:26, 40F

09/20 14:27, , 41F
select()和recvfrom() 有沒有錯誤, 尤其是在出現 EBADF
09/20 14:27, 41F

09/20 14:27, , 42F
和recvfrom卡住之前的那幾次select和recvfrom
09/20 14:27, 42F

09/20 17:53, , 43F
出錯前,每一次 select 都是 return >0 or =0
09/20 17:53, 43F

09/21 10:13, , 44F
之前的recvfrom()呢?
09/21 10:13, 44F
文章代碼(AID): #1ESPFajI (Linux)