如何缩短SocketConnection的连接超时时间?(200分)

  • 主题发起人 主题发起人 dq
  • 开始时间 开始时间
D

dq

Unregistered / Unconfirmed
GUEST, unregistred user!
当SocketConnection试图Connect一个错误的IP时(如该IP指向的机器没开机),返回时间长得难以忍受:(
请教各位大虾如何解决?
 
scoketconnection不是有设置时间的PORPERTY吗?
 
to zengr:能否告知是哪个属性?
另:“先ping一下”的答案不要。
 
我回去看看吧!
 
看属性怎莫不用帮助呢?!
 
to 雨人:不是没看帮助,是没发现有控制超时的属性啊。
 
我看了半天,真的没有这种属性,source code 里面也没有任何线索。
猜想可能与Windows内部的设置有关,如果要改的话,可以找找相关的API函数,可能
有解决方案。
 
我没发现过有这个问题,只有使用主机名才会有,
IP应该不会的,奇怪呀?
 
一刀兄:
不知道这个问题是不是和硬件环境有关。
我同事说他在一台笔记本上测试的时候,如果用一个跟本机不在同一网段的IP,则返回地挺快。
但在我的机器上不管用什么样的IP结果都一样,而且反而是用HOST的返回要快一些。
我再把问题说详细些——
程序设置:
我在scktcomp.pas的源码中如下的几个地方利用GetTickCount把运行时间显示在主界面上:
TCustomWinSocket.DoOpen过程中的CheckSocketResult(WinSock.connect(...之前
CheckSocketResult过程中的raise ESocketError.CreateResFmt(...之前
——以上两处是针对用IP的情况;
TCustomWinSocket.LookupName过程中的HostEnt := gethostbyname(PChar(Name));前后
——以上两处针对用HOST的情况;
主程序里调用SocketConnection1.Connected := True;之前以及它的except处理语句中
——记录连接初始时间和返回时间。
运行环境:
PⅢ 800、128M RAM、中文WIN98第二版,启动$(DELPHI)/Bin/scktsrvr.exe;
SocketConnect的Port为211、ServerGUID和ServerName属性均设为正确值。
运行结果:
用错误的IP——走到connect之前用时3毫秒;到connect出错用时45秒;再用2毫秒回到主程序。
用错误的HOST——走到gethostbyname之前用时2毫秒;之后用时11秒;再用3毫秒回到主程序。
——其中的时间都是大概的情况。
正如Infernal Goddess所说,通过对源码的跟踪也没有看到直接的解决办法:(
API里是不是只有setsockopt可以控制超时?
但是帮助里对setsockopt又有这么一个说明——
BSD options not supported for setsockopt are: ...SO_SNDTIMEO...
试了一下——
在sconnect.pas的TSocketTransport.SetConnected过程中的FClientSocket.Open;之前加上:
nTimeOut := 1000;
nLen := SizeOf(Integer);
if setsockopt(FSocket.SocketHandle, SOL_SOCKET, SO_SNDTIMEO, PChar(@nTimeOut), nLen) <> 0 then
...
——结果确实总是调用失败。
不知有没有办法解决这个问题……
 
上次ZGF也问了这样的问题,我也试了一下,的确有,最惨的结果是用了45秒才返回了 连接错误
换ICS的控件好像就没有了,
我也听听
 
setsockopt是不行的,那是连接成功后才能用
其它的不知道了,我的机器也有类似情况,不过感觉并不完全是socket的原因,
因为我直接用一个clientsocket就没有这问题(我用win2k)
 
一刀兄,你的ClientSocket.ClientType是不是用的默认的ctNonBlocking?
(而NonBlocking的ClientSocket在连接时用的是AsyncInitSocket)
如果你在ClientSocket的OnError事件里加上一个时间显示,
并且多等一会儿(我这里还是45秒左右)的话就会看到还是有问题的。
也就是说虽然ClientSocket.Active := True;这一句可以立即返回,
但是实际建立连接的出错返回时间是一样的(最终还是死在connect那一句上)。
而在用SocketConnection连接的情况下,可以看到:
当程序走到sconnect.pas的TSocketTransport.SetConnected过程中的
FClientSocket := TClientSocket.Create(nil);之后有这么一句——
FClientSocket.ClientType := ctBlocking;//源代码中的1740行
——如果你把ClientSocket.ClientType也改为ctBlocking,会发现结果是一样的:(
(用try...except...可以截到返回时间,类似我上次的作法)
所以目前对这个问题还是要唱:哎(爱)依然存在,不愿消失得太快!(黑豹.怕你为自己流泪)
 
TO:一刀
>>因为我直接用一个clientsocket就没有这问题(我用win2k)
我也就用了一个clientsocket,还是有问题,
(我也是2000,LAN)
你试试看有没有,代码在这里:5K
http://uam.my.west163.com/error/client.zip

继续听
 
不知得到超时的时间能不能解决这个问题(用WINDOWS API 函数)
 
to LAN:
是的,有问题,我之所以没发现是因为别的原因,抱歉 :-))
to all:
Winsock确实没有这种能力,据说别的(BSD)socket也没有。
网上有讨论,用一点hacker的手段能办到,但是有没有害处,就不得而知了。
 
to 安彤:能否再说得具体一些?
to all:请继续...
 
这个问题我碰到过,我解决的方法是,脱离网络控件本身,下面是我取国际时间的片断
因为GMT时间服务器的IP有的时候是不通的,或者是忙。
Function TzjNetS_F.GetGJ_Time:Boolean;
//获得国际时间
var
a:byte;
S:string;
begin
for a:=1 to 6do
begin
zj_GJTimeFalg:=0;
zj_DateTime:=0;
S:=Decrypt(TimeIP[rand(1,GJ_TimeIP)]);
l7.caption:=s;
try
timer1.Enabled:=True;
cli.Address:=S;
cli.Open(TDatagramSocket);
TDatagramSocket(cli.Conn).Text:='yezi';
except
timer1.Enabled:=False;
end;
while zj_GJTimeFalg=0do
Application.ProcessMessages;
if zj_GJTimeFalg=2 then
begin
l2.caption:=DateTimeToStr(zj_DateTime);
zjNetS_F.caption:=datetostr(IntToDateTime(zj_intGJTime+GetTickCount-zj_intPCTime));
result:=True;
cli.Conn.Close;
exit;
end;
if zj_GJTimeFalg=1 then
cli.Conn.Close;
end;
result:=False;
l2.caption:='出错';
cli.Conn.Close;
end;

procedure TzjNetS_F.Timer1Timer(Sender: TObject);
begin
timer1.Enabled:=False;
cli.Conn.Close;
zj_GJTimeFalg:=1;
end;

procedure TzjNetS_F.cliRead(Sender: TObject;
Socket: TSocketBase);
var
cnt:integer;//UDP时钟值
thetime:longint;
begin
cnt:=Socket.Recv(thetime,4);
Application.ProcessMessages;
if cnt=4 then
begin
zj_intGJTime:=WinSockAPI.ntohl(thetime);//长整型的国际时间变量,通过UDP查找
zj_DateTime:=IntToDateTime(zj_intGJTime);//转换为日期型
zj_intPCTime:=GetTickCount;//长整型的本机时间变量GetTickCount
zj_GJTimeFalg:=2;//获得国际时间成功
end
else
begin
zj_GJTimeFalg:=1;//获得国际时间失败
end;
end;

上面有的的过程属于强制等待,我把它放入线程绕过独占
 
人生得意须尽欢,有酒只合今朝醉!
本周结束。
 
找了半天都没有发现,真是对不起!
 
嘿嘿,上次我说有解决办法,就是通过一些XX手段,
因为是需要直接修改scktcomp.pas,觉得意义不大,所以就没帖代码。
如果还有兴趣,我可以把代码帖上来。
 
后退
顶部