• 全部
  • 语言基础/算法/系统设计
  • 数据库相关
  • 图形处理/多媒体
  • 网络通信/分布式开发
  • VCL组件开发及应用
  • Windows SDK/API
  • 问答

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

DDGG 上海飞书数字科技有限公司 开发组长/高级工程师/技术专家  2002-05-14 07:14:25
运行环境:WindowsXP + Delphi 6.0

要求:使用一个TClientSocket尝试与尚未运行的TServerSocket服务端应用程序连接,力求在TServerSocket运行后尽快与之建立连接并通信,因此使用一个TTimer定时为1秒不断尝试连接。

注意:TServerSocket平时是关闭的,很少开启,而TClientSocket要在其开启后尽最大努力尽快与之连接。

另外:TClientSocket和TServerSocket均采用ctNonBlocking(非阻塞方式)。

在TClientSocket的OnError事件中屏蔽连接失败错误:
procedure TForm1.ClientSocket1Error(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
var ErrorCode: Integer);
begin
ErrorCode := 0;
end;

定时器中代码如下:
procedure TFrom1.Timer1Timer(Sender: TObject);
begin
if not ClientSocket1.Active then ClientSocket1.Active := True;
end;

结果:TServerSocket服务端应用程序启动时,TClientSocket能正常与TServerSocket连接,但如果TClientSocket运行一段时间后仍未启动TServerSocket服务器(大约10分钟),TClientSocket应用程序就会出错!

错误为:Project BNTester.exe raised exception class ESocketError with message 'Windows socket error: 当该操作在进行中,由于保持活动的操作检测到一个故障,该连接中断。(10055), on API 'connect". Process stopped. Use Step or Run to continue.

继续运行还会引发另一个错误:Project BNTester.exe raised exception class ESocketError with message 'Windows socket error: 提供的文件句柄无效。(10022), on API 'WSACancelASyncRequest"". Process stopped. Use Step or Run to continue.

我初步分析是由于Socket句柄资源用尽导致的,有什么方法可以解决?
...全文
1116 点赞 收藏 18
写回复
18 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
sunhuiNO1 2002-05-15
用一个单独的线程连接,这个线程用阻塞方式。就不会出现你说的问题,
回复
lizhenjia 2002-05-15
开始->程序->delphi6->help->ms sdk help->windows socket 2 reference
然后键入 error codes
回复
DDGG 2002-05-15
To: lizhenjia(暴雪)

谢谢你!
回复
DDGG 2002-05-14
TO: lizhenjia(暴雪)

> 10055错误:
> WSAENOBUFS
>
> (10055)
>
> No buffer space available.
>
> An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.

你在哪里找到指定错误号的解释的?我怎么在Help里找不到?
回复
DDGG 2002-05-14
To: 猛禽

>直至连上后再断开,改回NonBlocking方式
这么做有点牵强,如果一连接上,Server就要主动向Client发送数据呢?

你的意思是说如果两端都用Blocking方式就没有问题了?
回复
猛禽 2002-05-14
最简单的解决办法是将ClientSocket改用Blocking方式试连,
直至连上后再断开,改回NonBlocking方式
回复
lvloj 2002-05-14

procedure TFrom1.Timer1Timer(Sender: TObject);
begin
try
clientsocket.open;
Timer1.Enable := False;
except
ClientSocket.Close;
end;
end;

ClientSocketOnDisConnect事件:
Timer1.Enable := True;
回复
DDGG 2002-05-14
To: hieefxz(凡人邪真)

lizhenjia(暴雪)说的没错。
回复
DDGG 2002-05-14
To: plainsong(轻风)

你说的方法我试过的,使用Timer还是使用线程都可以(Timer本身就是一个线程)。我是这么做的:在OnTimer事件里再多判断一个条件(即本次连接是否完成):
procedure TFrom1.Timer1Timer(Sender: TObject);
begin
if not ClientSocket1.Active and not F_Connecting then
begin
F_Connecting := True;
ClientSocket1.Active := True;
end;
end;

在ClientSocket1的OnError和OnDisconnect事件中增加一行:
F_Connecting := False; // 本次连接结束,可以再次进行连接。

结果还是一样的,也许如同“Thumb168(大母指)”所说,只要TClientSocket未消亡,它所用过的SocketHandle就不会释放?
回复
DDGG 2002-05-14
To: plainsong(轻风)

你说的方法我试过的,使用Timer还是使用线程都可以(Timer本身就是一个线程)。我是这么做的:在OnTimer事件里再多判断一个条件(即本次连接是否完成):
procedure TFrom1.Timer1Timer(Sender: TObject);
begin
if not ClientSocket1.Active and not F_Connecting then
begin
F_Connecting := True;
ClientSocket1.Active := True;
end;
end;

在ClientSocket1的OnError和OnDisconnect事件中增加一行:
F_Connecting := False; // 本次连接结束,可以再次进行连接。

结果还是一样的,也许如同“Thumb168(大母指)”所说,只要TClientSocket未消亡,它所用过的SocketHandle就不会释放?
回复
lizhenjia 2002-05-14
to hieefxz(凡人邪真)
你的方法是不行的,这种在onerror事件中和在ontimer中 尝试重连接又有何区别呢?只是你连接的次数少而已,我早就是过了,你可以把server关掉,然后在onerror事件中如果errorcode=10061就不断重联,30--70次保证程序down掉!
回复
hieefxz 2002-05-14
方法太土了。不用Timer控件。在OnError事件里处理,当你连接时如果失败返回错误,这时进行处理:
form1.ContinueConnect
begin
clientsocket.active:=false;
try
clientsocket.address:='127.0.0.1';
clientsocket.port:=6677;
clientsocket.active:=true;
except
abort;
end;
end;
该过程在错误处理中调用,我试过了是可以的。
就是server关闭时,
要在Disconnetion事件中再进行处理。
回复
riddler 2002-05-14
关注
回复
短歌如风 2002-05-14
不要用Timer控件,改用线程去做.
在线程里循环进行连接,每次连接前等待一个事件,这个事件由TClientSocket.OnError中的代码触发,直到连接成功或线程被终止.以保证每次连接时,上一次的连接已经断开.

____ ____
\ p \ / g /
\ l \_/ n /
\ a o /
\ i s /
\ n /
\_/
回复
DDGG 2002-05-14
To: Thumb168(大母指)
为什么我认为是Socket句柄(SocketHandle)资源用尽的问题呢?因为我曾在OnTimer事件里监视过ClientSocket1.Socket.SocketHandle 。
procedure TFrom1.Timer1Timer(Sender: TObject);
begin
if not ClientSocket1.Active then ClientSocket1.Active := True;
// 曾在此处以写Log日志文件方式监视过程序运行过程
// 中ClientSocket1.Socket.SocketHandle,发现此值每次总会以+2~+8
// 速度递增,最后达到3万多的时候就是程序出错之时。
end;


在Timer触发事件里创建TClientSocket、进行连接,还要释放,再退出OnTimer?这好像有点奇怪,因为连接成功与否要通过TClientSocket的OnConnect、OnError事件被触发来得知的啊!

你的意思是一旦TClientSocket的实例被释放,它所使用过的资源(比如SocketHandle)也就还给系统可以重新分配使用了?
回复
lizhenjia 2002-05-14
10055错误:
WSAENOBUFS

(10055)

No buffer space available.

An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.
回复
lizhenjia 2002-05-14
这个问题我也曾经遇到过,强烈关注解决办法,不过最好的办法就是不要这么无限制地连接下去
因为出现这种问题的原因是客户机的缓冲区或者队列满了,系统缺乏资源,如果在连接下去windows离down就不远了.纤细请查看sdk帮助.
回复
Thumb168 2002-05-14
你的推测不下确,你可以这样 试一下,在时间触发事件中动态申请一个TClientsocket来测试联接,如果能服务器启动了,哪么再调用静态的TClientSocket与之相联接。当然,别忘记要自己接管处理一些错误信息。好了试一下吧,应该可以的。也别忘记在时间触发事件结束时释放动态的TClientSocket
回复
相关推荐
综教楼后的那个坑用双向链表实现 描述   在 LIT 综教楼后有一个深坑,关于这个坑的来历,有很多种不同的说法。其中一种说法是,在很多年以前,这个坑就已经在那里了。这种说法也被大多数人认可,这是因为该坑有一种特别的结构,想要人工建造是有相当困难的。   从横截面图来看,坑底成阶梯状,由从左至右的 1..N 个的平面构成(其中 1 ≤ N ≤ 100,000),如图:    *            * :    *            * :    *            * 8    *    **      * 7    *    **      * 6    *    **      * 5    *    ********* 4 <- 高度    *    ********* 3    ************** 2    ************** 1 平面 |  1  |2|   3    | 每个平面 i 可以用两个数字来描述,即它的宽度 Wi 和高度 Hi,其中 1 ≤ Wi ≤ 1,000、1 ≤ Hi ≤ 1,000,000,而这个坑最特别的地方在于坑底每个平面的高度都是不同的。每到夏天,雨水会把坑填满,而在其它的季节,则需要通过人工灌水的方式把坑填满。灌水点设在坑底位置最低的那个平面,每分钟灌水量为一个单位(即高度和宽度均为 1)。随着水位的增长,水自然会向其它平面扩散,当水将某平面覆盖且水高达到一个单位时,就认为该平面被水覆盖了。   请你计算每个平面被水覆盖的时间。    灌水 水满后自动扩散 | | * | * * | * * * * V * * V * * * * * * .... * *~~~~~~~~~~~~* * ** * *~~~~** : * *~~~~**~~~~~~* * ** * *~~~~** : * *~~~~**~~~~~~* * ** * *~~~~**~~~~~~* *~~~~**~~~~~~* * ********* *~~~~********* *~~~~********* *~~~~********* *~~~~********* *~~~~********* ************** ************** ************** ************** ************** **************    4 分钟后    26 分钟后        50 分钟后    平面 1 被水覆盖     平面 3 被水覆盖    平面 2 被水覆盖输入   输入的第一行是一个整数 N,表示平面的数量。从第二行开始的 N 行上分别有两个整数,分别表示平面的宽度和高度。 输出   输出每个平面被水覆盖的时间。
发帖
Delphi
创建于2007-08-02

4890

社区成员

Delphi 开发及应用
申请成为版主
帖子事件
创建了帖子
2002-05-14 07:14
社区公告
暂无公告