是否是Delphi的一个bug(关于Twinsocketstream.WaitForData)(200分)

Z

ZHC

Unregistered / Unconfirmed
GUEST, unregistred user!
我在编写一个Email软件时,使用了阻塞式Winsocket调用,
用TwinsocketStream类读写winsocket,在程序中为了解socket
端口是否已经准备好,我使用了Twinsocketstream的一个成员函数
WaitFordata,根据Delphi的帮助文件说明,在使用Twinsocketstream
读写(注意这里是说“读写”)之前要调用WaitFordata函数,以测试
Socket端口是否准备好接受读写。但是在使用中我发现,在向socket
端口写数据之前,用Waitfordata,它总是返回False(即端口没有准备好)
致使我的程序总处于等待壮态。
我察看了Delphi的源代码,waitfordata函数的代码如下:(在scktcomp.pas)
function TWinSocketStream.WaitForData(Timeout: Longint): Boolean;
var
FDSet: TFDSet;
TimeVal: TTimeVal;
begin
TimeVal.tv_sec := Timeout div 1000;
TimeVal.tv_usec := (Timeout mod 1000) * 1000;
FD_ZERO(FDSet);
FD_SET(FSocket.SocketHandle, FDSet);
Result := select(0, @FDSet, nil, nil, @TimeVal) > 0;
end;
发现里面有一个语句有问题即:
Result := select(0, @FDSet, nil, nil, @TimeVal) > 0;
select是winsocket Api函数,她的第二个参数的含义是:(可选)指针
,指向一组等待可读性检查的套接口。第三个参数含义:(可选)指针
,指向一组等待可写性检查的套接口。上面的语句实际上只是检查套接口的可读性,而不是可写性,因此在写端口之前,如果端口中已无数据可读
自然要返回False.于是,
我在Twinsocketstream里加了一个函数Waitfordatawrite,代码与
Waitfordata大致相同,只是最后一句改成:
Result := select(0, nil,@FDSet, nil, @TimeVal) > 0;
在写端口之前调用,
在程序中使用果然程序运行正常。
不知这是否是一个Delphi的bug ,我的理解是否正确,请高手指教
另外,我想问如果我不在读写端口前调用Waitfordata,为甚么
程序会产生进入异常,严重时会产生蓝屏的0E号错误(处于阻塞状态)。
还有在winsoket阻塞调用情况下,select函数的具体用法。
我准备了200分,奖给高手。



 
补充:我使用版本是Delphi3.0 C/S。
 
请详细说明一下,select函数的具体用法
 
4.0里面的

function TWinSocketStream.WaitForData(Timeout: Longint): Boolean;
var
FDSet: TFDSet;
TimeVal: TTimeVal;
begin
TimeVal.tv_sec := Timeout div 1000;
TimeVal.tv_usec := (Timeout mod 1000) * 1000;
FD_ZERO(FDSet);
FD_SET(FSocket.SocketHandle, FDSet);
Result := select(0, @FDSet, nil, nil, @TimeVal) > 0;
end;

使用中好象没问题.
 
我在实际使用中,无此问题
 
这个问题我很感兴趣,

能给我份你的源程序研究研究吗?

xwtao@163.net
 
我先谈谈看法:

WaitFordata确实只能保证让你无阻塞的读SOCKET。你为了保证无阻塞的写
对WaitFordata的修改也是对的。我认为DELPHI之所以只保证无阻塞的读,是
因为读阻塞是经常发生的,而写阻塞很少发生(写阻塞只在TCP缓冲区满以后
发生)且发生写阻塞后,会很快因为缓冲区有了空间后解除,而读阻塞有可能
永远也不能解除(若无时延)。这样在写程序时,建立好一个SOCKET连接后,
可直接用写SOCKET操作,在读SCOKET之前可调用WaitFordata以确保无阻塞的
读SOCKETE。

至于为何不调用WaitFordata会产生异常,甚至完全阻塞,我也很疑惑,
很想看看你的源程序,我想可能和Twinsocketstream的读SOCKETE采用
READFILE、写SOCKETE采用WRITEFILE有关。(因为联想到,正在读光驱
时拿出光盘,就会出现你所说的阻塞现象)。

这些只是我的看法,我要编程序实验,若你能提供你的源程序最好。

不过DELPHI在对WINSOCKT的几个封装使用上都不是很理想,比如:
TSERVERSOCKET,TCLIENTSOCKET。我认为还不如直接调用WINSOCKET函数
好。

望共同讨论、提高。
 
》WaitFordata确实只能保证让你无阻塞的读SOCKET?????????
不同观点:
阻塞方式中才使用wantforddata,阻塞方式类似于同步通讯。
 
我也遇到过同样的问题,但可以回避:
在读之前用waitfordata,写之前就不要用了,因为没有必要:
1.既然线程都建起来了,首次写肯定没问题
2.因为是阻塞模式,当你接到对方应答或请求时,网络也是ok了。
3.如果出错,屏蔽掉重来n次。
 
最近,我怎么也连不上大富翁站点,给斑竹发信也没有答复,今天用2911拨号才连上了站点,在此,对我没有及时答复各位的帮助,表示歉意.
我也认为,在写操作之前不必要调用waitfordata,程序可以正常运行,不过,delphi 3.0的文档说在写和读操作之前都要调用waitfordata, 有一定的误导.不知众位是否同意我的观点.
 
多人接受答案了。
 
各位老兄,本人用TServerSocket与TClientSocket互连时,为何
有以下情况:
1.TClientSocket.Address="127.0.0.1"时大约需时3s
2.TClientSocket.Address="200.200.200.2"(Server IP)时大约需时30s
因为速度难以忍受,故想请各位前辈指点
若是此两个TComponent的本身问题,那能用何TComponent代替,而且能丢在
Service上?
 
顶部