导航:
论坛 -> DELPHI技术
斑竹:liumazi,sephil
作者:
2014/5/27 20:31:22
标题:
TclientSocket 尝试连接多次会报 缓冲区不足
浏览:3704
加入我的收藏
楼主:
10多年前就遇到这个问题,但是一直没有解决; 如下面这个帖子: http://bbs.csdn.net/topics/70153564 我用了最彻底的方法:TclientSocket动态创建,如果一直连接服务端不成功,那么就freeandnil 后再全部重建, 但是时间长了,一样会报错; 后来做了一个最最彻底的方法,每次尝试连接1000次,如果再不连接成功,那么自动把整个exe程序重启;
----------------------------------------------
青云论坛
作者:
datm (dATM)
★☆☆☆☆
-
盒子活跃会员
2014/5/27 21:27:38
1楼:
10年了,你还不会用WinSock、API吗?
----------------------------------------------
-
作者:
2014/5/27 23:37:49
2楼:
你想做啥? 1000次? 有人重试那么多次的麽... 另外, tclientsocket是基于消息的. 在每次重连前, 你都必须确定内核对象被关闭了. 而且, 连接失败的话, 你要等待onerror出来才能进行下一次的连接尝试.
----------------------------------------------
--
作者:
2014/5/28 7:50:31
3楼:
TclientSocket 使用简单 ,可以用非阻塞; 用WinSock、API?自己直接写最底层,没必要这样吧; indy只有阻塞; 连接失败,确定了onerror之后才连接的;能想到的都想到了; 而且都已经freeandnil(TclientSocket) 在重建了;
----------------------------------------------
青云论坛
作者:
hs_kill (lzl_17948876)
★☆☆☆☆
-
普通会员
2014/5/28 8:53:29
4楼:
ClientSocket自己的BUG 他free的时候没有释放Socket句柄, 你可以观察一下重复create100次, 句柄每次都是增加1的 free的时候用API吧句柄释放了 Shutdown(_Socket.Socket.SocketHandle, SD_RECEIVE); _Socket.Socket.Close; WinSock.closesocket(_Socket.Socket.SocketHandle);
----------------------------------------------
http://www.cnblogs.com/lzl_17948876/
作者:
2014/10/21 17:47:28
5楼:
楼上兄弟的方法,我投入使用了; 还是不行; 在网上找到一段代码 (来自: http://www.ylzx8.cn/windows/delphi/56337.html ) ------解决方案---------- 在 ClientSocket 的OnLookup事件里,调整Socket的参数 (uses WinSock): procedure TForm1.ClientSocket1Lookup(Sender: TObject; Socket: TCustomWinSocket); var Bo_Dontlinger : BOOL; begin Bo_Dontlinger := True; SetSockOpt(Socket.SocketHandle, SOL_SOCKET, SO_DONTLINGER, @Bo_Dontlinger, sizeof(BOOL)); end; 准备试试;
----------------------------------------------
青云论坛
作者:
2014/10/26 23:24:01
6楼:
找到一个第三方的控件: http://uvc.sourceforge.net/ 已经安装,打算以后用这个代替; 毕竟该控件一直在更新,bug和性能应该好过delphi6以后就不更新的自带的 tclientsocket 和 tserversocket;
----------------------------------------------
青云论坛
作者:
2014/10/27 12:09:04
7楼:
http://bbs.csdn.net/topics/320178816
----------------------------------------------
青云论坛
作者:
2014/11/12 6:52:40
8楼:
使用了 在 ClientSocket 的OnLookup事件里,调整Socket的参数 (uses WinSock): procedure TForm1.ClientSocket1Lookup(Sender: TObject; Socket: TCustomWinSocket); var Bo_Dontlinger : BOOL; begin Bo_Dontlinger := True; SetSockOpt(Socket.SocketHandle, SOL_SOCKET, SO_DONTLINGER, @Bo_Dontlinger, sizeof(BOOL)); end; 照样报错: Windows socket error: 由于系统缓冲区空间不足或队列已满,不能执行套接字上的操作。 (10055), on API 'connect' 看来clinetsocket的顽疾搞不定了; http://bbs.csdn.net/topics/70153564
----------------------------------------------
青云论坛
作者:
zmzj (zmzj)
★☆☆☆☆
-
盒子活跃会员
2014/11/12 9:22:36
9楼:
自己写个不就可以了
----------------------------------------------
-
作者:
2014/11/12 9:41:35
10楼:
应该是哪里没处理好吧, 咱也用这个控件,在一个机器上连续不断地整,没发现这个错。 下面是一台机器上连续100万次访问服务器的测试,100%成功,没出错。
此帖子包含附件: 大小: 520.4K
----------------------------------------------
樵夫的大马甲
作者:
2014/11/12 9:44:09
11楼:
下面这个也是同一机器100万次访问服务器的测试,顺利完成。
此帖子包含附件: 大小: 384.5K
----------------------------------------------
樵夫的大马甲
作者:
2014/11/12 13:52:14
12楼:
我用TClientSocket用得比较多, 知道如何解决这些问题 问题1: 10多年前就遇到这个问题,但是一直没有解决;如下面这个帖子: http://bbs.csdn.net/topics/70153564 这个问题, 是由于使用了Timer. 原因是TClientSocket每发起一个连接, 如何目标不存在, 则要超时20秒后,才释放socket资源. 如果你用Timer间隔设置低于20秒的话, 不断地调用ClientSocket1.Close时, 实际上socket还没真正关闭;要等到20秒后才能真正关闭, 这时你又调用 ClientSocket1.Open, 又会再新建连接资源. 反复就会累积很多socket资源没释放. 但如果连接能连通的情况, 上面的问题是不存在的. 问题2: 4楼hs_kill说的没错, ClientSocket自己的BUG 他free的时候没有释放Socket句柄, 你可以观察一下重复create100次, 句柄每次都是增加1的 free的时候用API吧句柄释放了 这问题也是发生在连接不能连通的情况, 如果能通则问题也不存在的. 这应该算是delphi的bug 解决: 捕捉出错事件ClientError, 手工释放 procedure TForm1.ClientError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); begin ErrorCode := 0; ClientSocket.Active:= False; ClientSocket.Socket.Close; // 如果无这行, 则资源不会释放, 多到系统的Socket句柄会溢出 end;
----------------------------------------------
-
作者:
2014/11/12 13:57:32
13楼:
上面10楼和11楼的测试是TCP能连通的情况, 这是不会有什么问题的. 问题是目标不能连通的情况, 而且要过一段时间才能看到问题, 最简单在任务管理中把句柄调出来看,会不断增长.
----------------------------------------------
-
作者:
2014/11/12 14:11:19
14楼:
加一句Disconnect就好了。 原因很简单,在未连接成功时,active=true, close时并未将资源socketHandle释放。 算是个小BUG。 procedure TForm1.Timer1Timer(Sender: TObject); begin if ClientSocket1.Active then begin ClientSocket1.Socket.close;//Disconnect(ClientSocket1.Socket.SocketHandle); ClientSocket1.Close; end; ClientSocket1.Open; inc(i); caption:=intToStr(i); end;
----------------------------------------------
-
作者:
2014/11/12 14:15:21
14楼:
再认真年了这贴: 10多年前就遇到这个问题,但是一直没有解决;如下面这个帖子: http://bbs.csdn.net/topics/70153564 其实帖子下面的解决方法是OK的, qzxyd提出的问题, 其实下面DDGG等几位已经说出解决办法了, 和我的一样, 够清楚了, 只是DDGG提到要ClientSocket.Socket.close才能解决, 但qzxyd一直都误解成了ClientSocket.close, 这是不一样, 误认了, 问题就没法解决了. 别外xjlqlqlq也指出Timer时间不能设置太短, 楼主还是没听进去, 坚持Timer时间长短无关, 所以也是个原因.
----------------------------------------------
-
作者:
2014/11/13 10:02:32
15楼:
不会吧,我加上了两句代码,确实没有出现泄漏的情况了,在Onclienterror中,并且会触发OncilentDisConnect ========== unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Win.ScktComp, Vcl.StdCtrls, sLabel, sButton, sMemo, Vcl.ExtCtrls; const WM_ReConnect = WM_USER + $0001; type TForm1 = class(TForm) ClientSocket1: TClientSocket; sButton1: TsButton; sLabel1: TsLabel; sMemo1: TsMemo; Timer1: TTimer; procedure sButton1Click(Sender: TObject); procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); procedure ClientSocket1Disconnect(Sender: TObject; Socket: TCustomWinSocket); private { Private declarations } public { Public declarations } procedure OnWM_ReConnect(var Msg : TMessage); message WM_ReConnect; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.ClientSocket1Disconnect(Sender: TObject; Socket: TCustomWinSocket); begin sMemo1.Lines.Add(DateTimeToStr(Now) + ': ClientSocket1Disconnect'); end; procedure TForm1.ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); begin ErrorCode := 0; sMemo1.Lines.Add(DateTimeToStr(Now) + ': ClientSocket1Error'); ClientSocket1.Active:= False; ClientSocket1.Socket.Close; // 如果无这行, 则资源不会释放, 多到系统的Socket句柄会溢出 PostMessage(Handle,WM_ReConnect,0,0); end; procedure TForm1.OnWM_ReConnect(var Msg: TMessage); begin if not ClientSocket1.Socket.Connected then begin ClientSocket1.Host := '127.0.0.1'; ClientSocket1.Port := 999; ClientSocket1.Open; end; end; procedure TForm1.sButton1Click(Sender: TObject); begin PostMessage(Handle,WM_ReConnect,0,0); end; end.
此帖子包含附件: 大小: 706.8K
----------------------------------------------
delphi加油!!
作者:
2014/11/13 11:29:57
16楼:
运行了差不多2个小时了,也没有泄露
此帖子包含附件: 大小: 426.0K
----------------------------------------------
delphi加油!!
作者:
2014/11/18 11:00:54
17楼:
楼上没用timer, 假如你在FormCreate中加入下面代码, 估计会看到句柄会增长 Timer1.Interval:= 1000; Timer1.Ontimer := sButton1Click; Timer1.Enable := true;
----------------------------------------------
-
作者:
2014/11/18 12:03:07
18楼:
上面, 其实更简单的方法, 手工不断地按Button1, 你就会发现Handle不断地增长.
----------------------------------------------
-
作者:
2014/11/20 22:37:25
19楼:
其实,我用的方法也很简单,和楼上alphacontrols 方法基本一致; 不够不确认到底真的解决没有: 1.如果尝试连接不上,那么自然会跳到onerr事件; 在该事件里加上: errcode:=0; //否则会弹出错误; socket.close;//这句话不清楚为什么要写,如果写了会触发onDisconnect事件; 2.这个才是最关键的:一定要等onerror事件触发之后,才能再次open; 所以在timer的时候搞一个锁变量,当open的时候,锁住;在连接成功或失败的时候,解锁;如果没有得到onerror 事件,就要一直等待下去,才能再次open; 这个确实有时短有时长,多则10多秒,少则1,2秒; 这毕竟是非阻塞的,所有在未得到成功或失败的响应之前不能再次open,道理上也是说的通的; madwolf (林之白狼)朋友提供的: PostMessage(Handle,WM_ReConnect,0,0); 也许确实能解决问题,不过感觉使用原始api,还是太“猛”了,会不会有其他并发症;
----------------------------------------------
青云论坛
作者:
2014/11/20 23:05:02
20楼:
很简单的原理,使用TTimer,你设置间隔为1秒,到时间系统自动调用Ontimer事件,他又不管你连接上没连接上,所以每次Ontimer都会去打开,这样句柄自然会增加,直接在OnClientEroor中去触发这个事件,发个消息最简单了
----------------------------------------------
delphi加油!!
作者:
2014/11/21 1:10:29
21楼:
很好,有技术含量
----------------------------------------------
-Courage is rightly esteemed the first of human qualities, because it is the quality which guarantees all others.
作者:
2014/11/21 11:32:39
22楼:
…… 被禁用帐号,帖子内容自动屏蔽! ……
----------------------------------------------
SPAM
作者:
2014/11/23 1:15:54
23楼:
按照楼上几位大侠的嘱托,做了个简单的实验,结果证明,TclientSocke 可以持续运行,不过代价是内存会泄露,不管是用 timer 定时器,还是手动点击,也无论是多少秒,或者多少分钟后释放 socket, 只要是释放 socket 后,再 open, 这样反复的 open 或 close, 内存泄露就会一点点的增加,直到该应用的所能够占用的资源被耗尽。 汇报完毕。测试平台 WIN7 SP1 64 位 或 WIN 20008 R2 64 位.
----------------------------------------------
-Courage is rightly esteemed the first of human qualities, because it is the quality which guarantees all others.
作者:
2014/12/22 12:44:22
24楼:
楼上的,我开了一个程序,15个clientsocket,重连的时候,必须等socket onerror触发后释放; 连续运行了3天;都没问题; win7 32位操作系统
----------------------------------------------
青云论坛
作者:
2015/9/11 16:43:03
25楼:
呵呵,我是楼主, 这是好久前发的帖子了,问题已经彻底解决了; 就是一句话: 在未收到onerror事件前不能重连; 或者说:onerror和重连必须1对1同步处理; 很多人都是TServerSocket/TClentSoceket不好; 推荐indy,但是indy因为阻塞的,个人喜欢非阻塞模式; 网上有人推荐: http://sourceforge.net/projects/uvc/files/ 不知道这个好在哪里;性能更高,更稳定; 还有rtc里面也有一个TCPSOCKET; 个人感觉应该差不多吧; 不知道手机andiroid下面,fmx环境下, TServerSocket/TClentSoceket还能否使用了;
----------------------------------------------
青云论坛