所有搞三层开发的高手,请进,帮帮忙!(200分)

  • 主题发起人 主题发起人 winmax
  • 开始时间 开始时间
不知道为什么,每次我发贴提出的问题,都是很少人能给出解决的方案的.晕了!..
 
borland server socket可带参数运行,加一个参数/install运行它就可以注册成NT服务,/UnInstall可撤销注册,从原代码中很容易找出可用的参数.
 
建议:
1 把你的scktsrvr换成d2006里面的,那个挺好的。
2 服务器是多线程的,检查你的程序是否使用了某些外部资源,但是这些外部资源没有进行线程保护,我以前的程序出现这个问题就是这个原因。
 
2。应该定时刷新users页,防止非法断开的情况,比如定时查看用户,未活动时间超过x秒(比如30秒)的,删除之

我认为这个很难实现的. 因为 数据模块是多实例的.你要删除这个实例才行.
而且也许就算你删除了实例,socksvr 还在维护着连接.
我不知道很多人这样回答,是你们都实际上这样做过,还是听别人说的?
如果你们是自己做 socket 服务器那这个比较容易.因为用 Borland socket server .这个基本上很难.
 
顶一下。
 
说得不错,顶
 
偶来凑凑热闹。
前些日子,和群里面的兄弟讨论过这个问题,为此,还说了另外的一些话题,比如三次握手,滑动窗口,消息边界,心跳函数之类。如果不清楚的,请补习一下相应的知识吧,这可是底层原理,不清楚,自然不晓得为什么,客户端异常断开,服务器端侦测不到。
从根源上说,这是由于TCP协议的问题。TCP协议的初衷是: 网络中断时,仍能维持通信的能力。美国国防部要求能在遭到核打击或其它灾害的时候,仍然能维持计算机之间可靠的网络通知协议。呵呵,如果客户端断开,服务器就马上释放连接。还维持什么?和初衷不符吧。要搞清楚客户端断开,为什么服务器端不能立即侦测到。这个问题,必须要理解三次握手机制。当然服务器也能侦测到异常断开,KEEPALIVE的默认时间是2小时哟。
详细的TCP三次握手机制:
客户端发送一个带SYN位的请求,向服务器表示需要连接,假设请求序号号为 SYN = 10, ACK=0
服务器接收到这样的请求后,查看是否在LISTEN的是指定的端口,不然,就发送RST=1应答,拒绝建立连接。 如果接收连接,那么服务器发送确认,SYN为服务器的一个内码,假设为100,ACK位则是客户端的请求序号加1,本例中发送的数据是:SYN=100,ACK=11,用这样的数据发送给客户端。
客户端发送确认建立连接的消息给服务器。确认信息的SYN位是服务器发送的ACK位,ACK位是服务器发送的SYN位加1 。
如果TCP连接第三次握手中,用户向服务器发送了一个SYN后就掉线了(第一步)。服务器发出SYN+ACK应答报文(第二步)。然后就再也无法收到客户端的ACK报文的。这种情况下,服务器就不断的重试,(再次发送SYN+ACK给客户端),直到超时。注意:服务器是接收到SYN请求就立即与客户端建立连接,而是先为连接请求分配内存空间,建立会话,并放到一个等待队列中。如果,这个等待的队列已经满了,那么,服务器就不在为新的连接分配任何东西,直接丢弃新的请求。这就是服务器的拒绝服务了。
因此,如果有人写一个恶意程序来试试你的Borland socket server,后果实在不敢去想。知道了问题的原因,也就能找出解决办法。解决办法就是用心跳函数。
在TCP中有一个Keep-alive的机制可以检测死连接,原理很简单,TCP会在空闲了一定时间后发送数据给对方:
1.如果主机可达,对方就会响应ACK应答,就认为是存活的。
2.如果可达,但应用程序退出,对方就发RST应答,发送TCP撤消连接。
3.如果可达,但应用程序崩溃,对方就发FIN消息。
4.如果对方主机不响应ack, rst,继续发送直到超时,就撤消连接。这个时间就是默认
的二个小时。
用keep_alive可以检测死连接,并撤消连接。但是是不是我们希望的呢?可能是,可能不是。有时可能我们希望重新通过另一个连接,来实现系统正常运转。
keep_alive实现:
type
TCP_KeepAlive = record
OnOff: Cardinal;
KeepAliveTime: Cardinal;
KeepAliveInterval: Cardinal
end;

var
Val: TCP_KeepAlive;
Ret: DWord;
begin

Val.OnOff:=1;
Val.KeepAliveTime:=xxx;
Val.KeepAliveInterval:=xxx;
WSAIoctl(AThread.Connection.Socket.Binding.Handle, IOC_IN or IOC_VENDOR or 4,
@Val, SizeOf(Val), nil, 0, @Ret, nil, nil)
end;
心跳函数:
客户端定时向服务器发送数据,表示自己存活着。在固定的时间内,服务器没有收到消息,就认为客户端已经断开,并释放连接。而这个过程也可以是双方的。即两边都有心跳机制。
Borland socket server 具体代码实现:
从派生TServerClientThread线程类。
THeartBeatServerClientThread= class(TServerClientThread)
private
cs : TCriticalSection;

protected
…….
procedure AddClient(vHeartBeat: THeartBeatServerClientThread);
procedure RemoveClient(vHeartBeat: THeartBeatServerClientThread);
end;

WorkThread: Array [0..MaxLink-1] of THeartBeatServerClientThread;
//连接队列
procedure THeartBeatServerClientThread.Execute;
var
theStream : TWinSocketStream;
begin

......
theStream := TWinSocketStream.Create(ClientSocket,120000);

While (not Terminated) and (ClientSocket.Connected)do
begin

try
if theStream.WaitForData(10) then
begin

Len := theStream.Read….
if Len=0 then
begin
//客户关闭连接
ClientSocket.Close;
end
else
begin

theStream.Write(Buffer,nLen);
end;

end;

except
ClientSocket.Close;
//Read和Write出错,断开连接。
end;

end;
 
scktsrvr+socketconnettion的三层连接方式.
效率就是低下,还很不稳定,等您用到100个终端的时候,估计就动不了了.
----------------------
正确的方法是用连接池
 
我是这样子做,客户端在连接服务器后,会与服务器之间建立一个Socket通讯,每隔一段时间向服务器发出在线信息,如果服务器在有效时间未收到客户端的信息,认为是断开了,这样服务器主动断开已有的连接,包括创建的RemoteDataModule都会释放,如果已经没有在线的客户端,整个服务器端程序会完全退出
 
如果是自动分配地址的话,client端的地址只有加上心跳包才能保持在线,否则地址一旦变化就会出现,掉线的现象.
 
如果服务器在有效时间未收到客户端的信息,认为是断开了,这样服务器主动断开已有的连接,包括创建的RemoteDataModule都会释放
-------------------------------
我想学习一下你是如何释放 RemoteDataModule 的。给点提示
 
在用scktsrvr+socketconnettion的三层连接方式.在网络环境不是很好的情况下,经常会在客户端发出某一命令后出现灾难性故障,有没有更好的办法解决?希望大家给点小弟建议!
 
还是用webservice做中间层好啊,就不会遇到这些问题了。
 
将socket server的Time out 设为30-60试试,我用timeout=60运行,发现比设为0好多了
 
en,设置一下Timeout,还有最好在客户端加一个TTimer,如1分钟,就调用一下RDM的一个无效处理,达到类似"心跳"处理。
你那问题有可能是连接由于长时间未有数据通行,死连,但SERVER没检测出来的原因吧。
另:
你说的
borland server socket fix
在哪DOWN的,不然上传到某个地方,给大家看看,没用过
 
to:winmax
我建议不用socketconnettion,改成用dcomconnection.而且更好,不用输入端口、IP。
 
用dcomcon连接另一台机器的mts组件,提示远程rpc服务器不可用,请问如何配置.另一台机器已经有delphi环境,另一台连情况一样.请问如何配置.
 
不知写三层用啥好,dcom+MTS如何?
 
如果希望 三层能够支持 100个用户以上 需要写个COM对象管理池pooling 再写个 数据库访问池 就能解决了
 
Borland socket server 有bug,需要修正就可以了
 
后退
顶部