Re: [問題] winsock網路程式

看板Programming作者 (初夏。)時間18年前 (2006/10/31 22:29), 編輯推噓0(000)
留言0則, 0人參與, 最新討論串5/5 (看更多)
※ 引述《jinming.bbs@bbs.wretch.cc (人生=無盡的任務)》之銘言: : ※ 引述《MLP2007.bbs@ptt.cc (NEW)》之銘言: : > 我的想法: : > 把socket設為block mode : > 若Data還沒收全 則程式會block在recv中 : > 如果recv回傳為SOCKET_ERROR代表有錯誤 : > 否則即代表buffer已經填好資料可以讀取了 : > 這樣說對不對? : > 我的寫法大概如下 : > UINT FileReceiveThread(LPVOID pParam) //Receive Thread Function : > { : > struct Packet pak; : > REGET: : > do{ : > if(recv(sock, (char*) &pak, sizeof(struct Packet), 0) == SOCKET_ERROR) : > { : > // recv error : > return 0; : > } : 我猜您遇到問題的原因是: : 照您這樣寫看起來是為了一次只讀取一個 struct Packet 的大小以方便程式撰寫 : 但是要注意,TCP底層並不知道你的資料傳到哪裡算是一個 Packet : 所以你可能在某一次收到的 pak 長度 < sizeof(struct Packet) : 這個情況在您定義 sizeof (struct Packet) > 4096(印象中正常TCP frame的大小) : 時很可能發生 : 但 < 4096 也不一定可以一次收滿。 : 因此還是要先存到一個 Buffer 再作切割,像是上面的寫法。 原po程式寫法的問題就在於上面所述, 因為你認為你傳給recv的buffer size(指sizeof(pak))是固定的, 所以底層應該也pass給你那個長度,否則就會傳SOCKET_ERROR, 但實際上recv()>0可能發生的情況有兩種,一種是剛剛好,另一種則是少於bytes數, (recv()的參數3只是用來指明前一個buffer有多大,而「不保證」會放滿) 雖然你後來有去判斷pak中的某一member資料是否正確, 但是如果這次資料只有收到一半(假設是pak1的前半段), 下次你又重收,則會導致下一次收到後面那一半(pak1的後半段), 這樣還好,反正又被判斷pak中的member資料不對,又丟掉重收, 但,最糟的可能,你實際可能會收到的資料是pak1的後半段和pak2的前半段, 最後可能造成收到錯誤的資料或者是不斷的丟掉資料, 這就是你程式寫法的問題。 回到這篇,如jinming的說法, 你應該採用buffer pool去收socket資料的方式,自己去切割出packet來才對, 原來的這種寫法,會讓收到的資料很難預期,正確性會跟效率成反比, 所以才會發生你講的,傳的越慢、正確率越高。 再補充,原po可能對於TCP/IP底層的buffer pool的情況不是很清楚, 也許可以嘗試看看幾種測試, 用很快的速度不斷送出資料,設一個很大的buffer慢慢的去收, 還有很慢的送出資料,也用很慢的速度去收, 觀察兩種情況的recv() return value有什麼差別。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 218.187.12.127 ※ 編輯: ankasc 來自: 218.187.12.127 (10/31 23:00)
文章代碼(AID): #15Hrt9RK (Programming)
文章代碼(AID): #15Hrt9RK (Programming)