诡异的TCP/IP on GPRS,诡异的TCP/IP断开,中国移动网疑似出现BUG 本帖最后由 delphi2012 于 2012-04-10 10:19:18 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 临晨用了网络调试助手测试了的。问题是同样的,就是在新连接已经上来的情况下,关闭老连接,新连接自动断开。从GRPS终端上看,是服务器主动断开的 验证Delphi端的办法: 运行服务器,然后用网络调试助手连接到delphi做的服务器,然后直接结束网络调试助手进程,再用网路调试助手连接服务器,这样服务器上应该有两个连接,一个有效一个异常,服务器尝试关闭异常的那个,看正常的那个网络调试助手是否还在线或者也被强制断开了。移动GPRS应该不会有这种低级错误。 谢谢回复。用软件还不能模仿,用网络助手模拟客户端,不管是在本地局域网还是跨越互联网,只要客户端一用任务管理器杀死,服务器就立马执行ondisconnect函数。看来得忽然断网了。但是那样连第二个程序也无法开启了。 我们公司的GPRS连接是用户UDP做的。用的是C++, 这个可能是DELPHI方面的问题。或者是通讯协议有什么地方不正确。可以考虑用户UDP做一下试试,我过这个GPRS通讯包是我的一个同事做的,我也不太懂。而且C++也不是我的强项。只能提供参考意见!嘿嘿! 目前去掉了程序,用网络助手,换成联通的手机卡,用串口助手直接操作SIM300,不启用终端的AVR程序,结果是一样的。就是没有换CMnet出口 没大看明白楼主的描述,你的意思是客户端断开后,服务器依然还存在原来的那个SOCKET连接是吗?这个需要用服务器来轮询,根据时钟节拍来清理断开的连接的 对,就是这个意思,问题就是清理断开链接的时候,新的连接也被断开了。比如,老链接是用的11.22.33.44连接的。后来断开了,设备重新上电后重新连接,这个新建立的连接IP地址可能就变化了,可能是11.22.33.55了。那么在服务器上,关闭SOCKET的时候,关闭原来的老的11.22.33.44对应的链接,这个时候,新建立的11.22.33.55的链接就断开了。实在是太搞笑了, 我不太懂得GPRS网络的运行原理,我初步推测,可能是移动的网络自动记录每个SIM卡的上网情况,当该设备断开的时候,移动服务器缓存了该设备对应的IP数据。当该设备重新上电,上了GSM网络的时候,服务器又把上一次的IP地址对应的缓存信息送到新IP地址上去了,而上一次的IP地址对应的是TCP的关闭信息,所以,新IP地址也就接受了这样的请求,就自动关闭了。 问题出现了!!无论调用的close 函数或者CloseDelayed。关闭的明明是已经半死掉的以前的socket会话,但是新的已经建立起来的会话,却会被关闭程序了。断线了。遇过类似情况 与GPRS无关 与 TWSocketServer具体实现有关 是你的程序问题 TWSocketServer也有责任好像 旧连接断线后 它的SocketHandl 就会失效 新连接 连上后会分配SocketHandl 值为旧连接的 因为已断开 这时 再断开旧连接 就变成断开了新连接 旧连接实际已断开 但 SocketServer状态不正确 服务端你是怎么关闭客户端的??按ip?还是俺ip+(peer)port?还是俺连接主机名(包括你自己定义的名称)?搞清楚了,你再查看是不是对这些都发送了断开信号。。 ------兄台,你说的貌似在理啊,我得研究一下。看来得本地抓包确认一下。我是用的表示socket客户端的client对象提供的方法进行断开的,也就是说,我是按照指针进行操作的,操作的依据就是对方最后一次发包时间跟当前对比,确认是否在线的。 我是在socket server的事件函数中,引用事件函数中代表客户端的参数,就是代表客户端的一个对象,然后使用这个对象提供的close函数。按照上一个兄台的意思,是指针未变,而指针对应的对象已经悄悄发生变化了,所以就是老指针操作了新对象了。 ICS我没用过.我的工具用的是lazarus, + indy 10.我发现在onconnect,或ondisconnect事件就对客户端线程进行很多操作的话,服务端和客户端都很难断开,出现一些其他问题,发现有些连接线程会绕过onconnect事件.所以我把那些操作尽量放到onExecute事件中.譬如这样procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);begin AContext.Data:=TUserClass.create; {接入点跟断开点越简单越好,否则难以断开 一句话,所有的动作在execute里头由同步链进行} //with TUserClass(AContext.Data) do // begin // FContext:=AContext; // Fip:=AContext.Connection.Socket.Binding.PeerIP; // FPeerPort:=AContext.Connection.Socket.Binding.PeerPort; // FUserName:=''; // end;end; 希望这一看法能对你有帮助. CSDN里面有高人啊,CSDN里面有好人啊。高人,不是单一的技术层面的,还包括阅历,包括对软件产品的理解,见地。谢谢大家,我正在大规模改动代码。。如真是如此,马上结贴送分啊。 其实 TWSocketServer 是自带客户端断开检测的,正常客户端断开,会向服务器发送一个断开消息,服务器收到后出发 sessionclose,这里可以处理。可是有些客户端异常断开,服务器收不到断开消息,这样服务器就会一直保留这个socket,俗称死链接,其实可以用keepalive方法来定期检测客户端是否存活,这样TWSocketServer 会自动关闭死链接。 移动的GPRS 我们一直在用的,好像没有你说的问题,我觉得还是服务端问题吧。你试试让你的GPRS连接IIS看看他会不会这样。 回覆:很长时间才来。我抓包分析了。上位机close socket之后,自动发送FIN置位的IP包 ,IP是正常的,IP地址和端口都是对的上的,程序本身没有错误,这么简单的程序,要是有问题,那谁还敢用控件呢?自动发终结包,这是操作系统的自动行为,正常情况下就是该这么做,相同的IP甚至发送四五次。可见不见对方回应,因为抓不到对方的回包。 好,我投降,我不close socket还不行吗?但是这样的话,状态为ESTABLISHED的会话,成倍增加,从不断开,资源不得到释放,我的上位机程序还得一个个的遍历。也满 我的问题就是,象GPRS这种没有操作系统的、单线程的、靠SIM300等外置芯片实现TCP/IP协议的设备,到底该如何处理回话呢?难道让上位机定时重启吗? 我以前有过类似的,发现每隔一段时间断开,后来查出是的确是sim卡的问题,那个IP的是动态分配的每一段时间变一下,后来换了固定IP的就不会断了。 我们也遇到过类似的问题。 解决办法:1)客户端每隔一段时间发心跳包上来,如果超过时间没有收到心跳信号,就删掉socket2) 客户端每次连接的时候,主动发送一个设备id上来,你在设备编码时候保证id不重复。 如果断了重连时候,服务器端检测有重复的id,就把前面的id所对应socket删除。然后接受新的连接。 用一个数组管理在线的设备id即可。我们的应用是一个 gprs的中间件,可以支持上千 socket连接,用c写的,比用控件效率高一些。如果你的服务器端懒得写,可以调用我们的中间件,我们来帮你维持socket, 把收到的数据写入你的指定的数据库,或者开一个接口你来读。我们开发这个的目的就是降低大家写gprs服务器端的工作量。以在线saas方式运行。测试地址:http://184.169.160.55/GPRS_Free_Test/这个接口是针对gprs打印机的,可以根据你的需要写针对你的接口 其实定时GRPS断线的问题,我倒不担心。现在的测试,十几个小时都可以在线。关键楼上说的,删除SOCKET,结果就问题了。把正常的也给断开了。好像移动的网管系统太智能了,可以做到父债子还的地步。关闭老连接的时候,自动关闭新的连接。因为移动认为----你还是你,今天的你,就是昨天的你 我们讨论的是非正常的情况下的断开啊。 如果你的同一台设备再次连接上来,说明前面的已经断了,你只是在服务器数据结构上删除这个socket句柄,应该和移动网络没关系了,除非你又向客户端发出什么“我想断开”的信号,否则运营商不可能知道。你如果是用的线程,就直接关线程。进程,就直接关进程。 补充:我说的是c写程序自己控制socket握手情况下的判断,你用的这个控件我没用过,抱歉, 也许不适合你的情况 冒似楼主搞错了,调用控件的close应该是关闭整个TCP服务,所以所有的连接都会被断开.你要关某个特定的连接应该用别的方法 回避了SOCKET的问题。GPRS单独是一个对象,他根据SOCKET的最后活动时间来判定GPRS是否在线 delphi能在win7上运行吗?跟xp上开发有什么区别没有? 用集合类型编写程序,输入一个单词,统计其中元音字母的个数 ADO为什么要这么变态?还是我太菜?求教 各位大哥,如何在richedit控件上显示镜向字体,也就是反向字体??? TIdTCPClient的timeout问题 windows服务的相关问题 怎样才能把一个硬盘上的文件整个的存入数据库,又怎样提取。在线等待。 从一个表向另一个结构完全相同的表中追加记录,该怎么办?多谢! 怎样用delphi开发一个关闭程序并保存文件的控件呢? 怎样把StringGrid里面的内容打印出来? 输出调试信息的问题 CXgrid的使用
服务器就立马执行ondisconnect函数。看来得忽然断网了。但是那样连第二个程序也无法开启了。
对,就是这个意思,问题就是清理断开链接的时候,新的连接也被断开了。
比如,老链接是用的11.22.33.44连接的。
后来断开了,设备重新上电后重新连接,这个新建立的连接IP地址可能就变化了,可能是11.22.33.55了。那么在服务器上,关闭SOCKET的时候,关闭原来的老的11.22.33.44对应的链接,这个时候,新建立的11.22.33.55的链接就断开了。实在是太搞笑了,
是你的程序问题 TWSocketServer也有责任
好像 旧连接断线后 它的SocketHandl 就会失效 新连接 连上后会分配SocketHandl 值为旧连接的 因为已断开
这时 再断开旧连接 就变成断开了新连接 旧连接实际已断开 但 SocketServer状态不正确
按ip?
还是俺ip+(peer)port?
还是俺连接主机名(包括你自己定义的名称)?搞清楚了,你再查看是不是对这些都发送了断开信号。。
我是在socket server的事件函数中,引用事件函数中代表客户端的参数,就是代表客户端的一个对象,然后使用这个对象提供的close函数。按照上一个兄台的意思,是指针未变,而指针对应的对象已经悄悄发生变化了,所以就是老指针操作了新对象了。
我发现在onconnect,或ondisconnect事件就对客户端线程进行很多操作的话,服务端和客户端都很难断开,出现一些其他问题,发现有些连接线程会绕过onconnect事件.所以我把那些操作尽量放到onExecute事件中.
譬如这样
procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
begin
AContext.Data:=TUserClass.create;
{接入点跟断开点越简单越好,否则难以断开
一句话,所有的动作在execute里头由同步链进行}
//with TUserClass(AContext.Data) do
// begin
// FContext:=AContext;
// Fip:=AContext.Connection.Socket.Binding.PeerIP;
// FPeerPort:=AContext.Connection.Socket.Binding.PeerPort;
// FUserName:='';
// end;
end; 希望这一看法能对你有帮助.
可是有些客户端异常断开,服务器收不到断开消息,这样服务器就会一直保留这个socket,俗称死链接,其实可以用keepalive方法来定期检测客户端是否存活,这样TWSocketServer 会自动关闭死链接。
你试试让你的GPRS连接IIS看看他会不会这样。
很长时间才来。我抓包分析了。上位机close socket之后,自动发送FIN置位的IP包 ,IP是正常的,IP地址和端口都是对的上的,程序本身没有错误,这么简单的程序,要是有问题,那谁还敢用控件呢?自动发终结包,这是操作系统的自动行为,正常情况下就是该这么做,相同的IP甚至发送四五次。可见不见对方回应,因为抓不到对方的回包。 好,我投降,我不close socket还不行吗?但是这样的话,状态为ESTABLISHED的会话,成倍增加,从不断开,资源不得到释放,我的上位机程序还得一个个的遍历。也满 我的问题就是,象GPRS这种没有操作系统的、单线程的、靠SIM300等外置芯片实现TCP/IP协议的设备,到底该如何处理回话呢?难道让上位机定时重启吗?
我们也遇到过类似的问题。 解决办法:
1)客户端每隔一段时间发心跳包上来,如果超过时间没有收到心跳信号,就删掉socket
2) 客户端每次连接的时候,主动发送一个设备id上来,你在设备编码时候保证id不重复。
如果断了重连时候,服务器端检测有重复的id,就把前面的id所对应socket删除。然后接受新的连接。
用一个数组管理在线的设备id即可。
我们的应用是一个 gprs的中间件,可以支持上千 socket连接,用c写的,比用控件效率高一些。如果你的服务器端懒得写,可以调用我们的中间件,我们来帮你维持socket, 把收到的数据写入你的指定的数据库,或者开一个接口你来读。我们开发这个的目的就是降低大家写gprs服务器端的工作量。以在线saas方式运行。测试地址:
http://184.169.160.55/GPRS_Free_Test/这个接口是针对gprs打印机的,可以根据你的需要写针对你的接口
可以做到父债子还的地步。关闭老连接的时候,自动关闭新的连接。因为移动认为----你还是你,今天的你,就是昨天的你
补充:我说的是c写程序自己控制socket握手情况下的判断,你用的这个控件我没用过,抱歉, 也许不适合你的情况