TClientSocket不断尝试与TServerSocket连接,运行一段时间后的问题! (200分)

  • 主题发起人 叮叮当当
  • 开始时间
我分析了好半天,还是哪个TClientSocket里的FSocket就是TCustomWinSocket
我看了他的代码,很多地方没有看明白。
不过我对你的这个问题有一个很好的办法,
我在上一个帖子也是这么回的
那就是用一个单独的线程用阻塞式去连接这个服务器,如果连接上就postmessage
一个消息给主窗口。各位有什么意见?
 
用阻塞式重连就不会有SocketHandle耗尽的问题么?
 
我在做程序中,代码写了很多,一会就可以调试!
 
代码写好了,
 
to 叮叮当当:
1.你没有运行到断点,是因为你没有把vcl源码加入搜索路径。
2.阻塞式重连是不会有SocketHandle耗尽的问题,看一下源码
if Block then
begin
FAddr := InitSocket(Name, Address, Service, Port, True);
DoOpen;
end else
AsyncInitSocket(Name, Address, Service, Port, 0, True);
except
Disconnect(FSocket);
如果是阻塞方式出错,会被捕获并执行Disconnect(FSocket)。当然,如果你用
非阻塞方式,在OnError中执行Socket.Close,效果也是一样。
 
mywyn你的QQ是?
 
to 张无忌:
71553950,不过我老是忘记开QQ,已被朋友骂过N回了。^_^

 
很多人对socket API编程讳莫如深,其实没有有想像中的那么难,只用控件,对底层工作
难以深入理解,遇到控件难以解决的地方就无法。

一个socket客户端的工作步骤为:建立socket -> 连接服务器 -> 读写,先后需要调用的
函数为socket(), connect(), read()/write()或recv(), send()等。
每次运行socket()函数时,如果成功,就会打开一个句柄(在UNIX下叫“文件描述符”File
Descriptor),通常的编程是如果connect()失败,就应该关闭该句柄,而TCustomWinSocket
却没有这样做,所以打开的句柄数不断增加,操作系统充许一个进程打开的句柄数是有限的,
当达到这个值时,程序就要报错。

昨天我以每秒一次的频率用计时器定时连接服务器端,在OnError时关闭句柄。初始的
SocketHandle值为124,在3个值之间变动,运行一个小时后,SocketHandle增加到900,
其间出现了几次10038错误(不是Socket连接),每次出此错误的时候SocketHandle就要
增加,不知道它搞了些什么——而用API的话,一切都在自己的掌握中,很清楚。

现在我正在UNIX运行着程序试着,等两三个小时后再看结果。
 
谢谢大家!我开始尝试用TTcpClient控件代替TClientSocket连接TServerSocket,但是发现有时能连接成功,有时不行,发送数据也一样,也许是阻塞非阻塞的问题。另一个我想到用来替代TClientSocket的控件(ICS里的TWSocket)则也有古怪问题,它是通过State属性的改变来通知用户当前的通信状态的(State改变时会触发OnChangeState事件),State的值为以下枚举:wsInvalidState、wsOpened、wsBound、wsConnecting、wsConnected、wsAccepting、wsListening、wsClosed。可我发现这个控件不管是否连接成功都会出现wsConnected状态,只不过如果连接成功,State就不再变化,而如果是连接失败,则再出现wsClosed状态而已。倒~真是搞不懂ICS的作者是怎么想的!
 
我想这几天好好研究研究ICS控件
 
还想到过一个控件——Delphi自带的TPowerSock,可它没有接收、发送事件!*_*
 
TPowerSock看帮助说不能直接用,
 
To: 张无忌

>TPowerSock看帮助说不能直接用,
可我已经在程序中用它来测试连接速度了(因为只有它有TimeOut属性),使用很成功。
 
哦,我没有使用过,:)FastNet组件毛病多,很少用。
 
to 叮叮当当:
我仔细的看了ics源码,没有问题,你的情况可能是连上又断开了。假如你
只调用了Connect的话。另外还有一种情况要注意:你的Server端已在侦听,当有客户端
请求连接时由于某种原因没有调用Accept,此时客户端仍然显示连接成功。这跟控件
无关,用API函数也是一样。
 
To: mywyn

谢谢!但是我用ICS的TWSocket连接时,并没有开服务器程序呀,根本不可能连上才对。
你QQ不常开,那么你有MSN么?我的MSN:pschen@21cn.com,很想和你交个朋友!
 
to 叮叮当当:
不好意思,我没有MSN。你的情况我从来没遇到过。最好把你连接的代码贴一下。
另外,我的ics中的Wsocket.pas的版本为4.34。
 
To: mywyn
我的ICS中WSocket.pas的版本为4.40(这个是ICS最新的Beta版,我本以为是Beta版存在的问题,后来我又下载了最新的一个正式版,也是一样)。
证明这个问题的步骤如下:
1)新建一个Project,在窗体上放置一个TWSocket、一个TListBox、一个TButton;
2)为Button1添加OnClick事件处理代码如下:
procedure TForm1.Button1Click(Sender: TObject);
begin
SOCK.Addr := 'localhost'; // 每次调用 Connect 方法之前
SOCK.Port := '6112'; // 都必须重新设置 Addr、Port,麻烦。
SOCK.Connect;
end;
3)为WSocket1添加OnChangeState事件处理代码如下:
procedure TForm1.WSocket1ChangeState(Sender: TObject; OldState,
NewState: TSocketState);
const
_StateStringArray: array[TSocketState] of string = ('wsInvalidState',
'wsOpened', 'wsBound', 'wsConnecting', 'wsConnected', 'wsAccepting',
'wsListening', 'wsClosed');
begin
ListBox1.Items.Add(_StateStringArray[OldState]+' -> '+_StateStringArray[NewState]);
end;
4)按F9运行,点击按钮,你将会看到明明没有连接上却有wsConnected状态出现。
 
问题找到了:
Check := msg.lParamLo and FD_CONNECT;
if Check <> 0 then begin
if FState <> wsConnected then begin
ChangeState(wsConnected);
TriggerSessionConnected(msg.lParamHi);
if (msg.lParamHi <> 0) and (FState <> wsClosed) then
Close;
end;
end;
它把错误放到了最后判断,也就是这一句:
if (msg.lParamHi <> 0) and (FState <> wsClosed) then
Close;
有两种方法解决:1.是修改代码。
2.是调用Connect后,等待SessionConnected事件触发,然后
判断Error。
我因为一开始就是用的第二种方法,所以没有碰到你的这种情况。


 
顶部