作者ankasc (初夏。)
看板Programming
标题Re: [问题] winsock网路程式
时间Tue Oct 31 22:50:17 2006
※ 引述《[email protected] (人生=无尽的任务)》之铭言:
: ※ 引述《[email protected] (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)