Re: [問題] winsock網路程式
※ 引述《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)
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 5 之 5 篇):
Programming 近期熱門文章
PTT數位生活區 即時熱門文章