怎么样在indy server中检测到客户端的异常断线(例如断电),文章附部分程序(100分)

  • 主题发起人 主题发起人 soulmate
  • 开始时间 开始时间
S

soulmate

Unregistered / Unconfirmed
GUEST, unregistred user!
我的客户端其实是一个GPRS无线模块,大家可以把它当做一个客户端,我也查了网上的很多资料,都没有给处在客户端异常断线的处理办法。
按道理说应该在DisConnect事件中例如在Memo控件中显示断线的客户端IP地址,但我发现只要在Disconnect事件中调用显示程序就抛出异常,另外也根本检测不到客户端的断线问题。

这个问题一直也没有解决,希望有作过的或给指点一下,我想Indy既然做出这个东西,总不至于连这些细节都不能解决吧,一定是我那里没有搞明白~

unit Main;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Buttons, IdBaseComponent, IdComponent, IdTCPServer,
IdTCPConnection, IdTCPClient, IdAntiFreezeBase, IdAntiFreeze;



type
TMainFrm = class(TForm)
EdtPort: TEdit;
Meo_Rec: TMemo;
BtnStart: TBitBtn;
BtnSend: TBitBtn;
BtnStop: TBitBtn;
IdTCPServer: TIdTCPServer;
EdtSend: TEdit;
ChkSndHex: TCheckBox;
BtnAbout: TBitBtn;
BtnClear: TBitBtn;
IdAntiFreeze: TIdAntiFreeze;
procedure BtnStartClick(Sender: TObject);
procedure BtnStopClick(Sender: TObject);
procedure IdTCPServerConnect(AThread: TIdPeerThread);
procedure IdTCPServerExecute(AThread: TIdPeerThread);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure BtnSendClick(Sender: TObject);
procedure BtnAboutClick(Sender: TObject);
procedure BtnClearClick(Sender: TObject);
procedure FormCreate(Sender: TObject);

private
{ Private declarations }
public
{ Public declarations }
//function EncodeHEX(A : String) : String;
function EncodeHEX(A:PChar;len:Integer) : String;
end;

var
MainFrm: TMainFrm;



implementation

{$R *.dfm}

procedure TMainFrm.BtnStartClick(Sender: TObject);
begin
IdTCPServer.DefaultPort := StrToInt(EdtPort.Text);
IdTCPServer.Active := True;
BtnStart.Enabled := False;
BtnStop.Enabled := True;
Meo_Rec.Lines.Add('服务器已成功启动!');

end;



procedure TMainFrm.BtnStopClick(Sender: TObject);
begin
if (IdTCPServer.Active=true) then
begin
IdTCPServer.Active := False;
BtnStart.Enabled := True;
BtnStop.Enabled := False;
Meo_Rec.Lines.Add('服务器已成功停止!');
end;

end;

procedure TMainFrm.IdTCPServerConnect(AThread: TIdPeerThread);
begin
Meo_Rec.Lines.Add('来自主机 '
+ AThread.Connection.Socket.Binding.PeerIP
+ ' 的连接请求已被接纳!');

end;

procedure TMainFrm.IdTCPServerExecute(AThread: TIdPeerThread);
var
len:integer;
sCommand: array[0..4096] of char;
begin
if not AThread.Terminated and AThread.Connection.Connected then
begin
try
FillChar(sCommand,sizeof(sCommand),#0);
len:=AThread.Connection.ReadFromStack(false,-1,false);

if len>0 then
begin
AThread.Connection.ReadBuffer(sCommand,len);
Meo_Rec.Lines.Add('Asc显示为:'+sCommand);
Meo_Rec.Lines.Add('Hex显示为:'+EncodeHEX(sCommand,len))
end;

except

end;
end;

end;



procedure TMainFrm.FormClose(Sender: TObject; var Action: TCloseAction);
begin

IdTCPServer.Active := False;

end;

{function TMainFrm.EncodeHEX(A : String) : String;
var
N : Integer;
begin
N := Length(A);
SetLength(Result,N * 2 + 1);
BinToHex(PChar(A),PChar(Result),N);
end;}

function TMainFrm.EncodeHEX(A:PChar ;len:Integer) : String;
var
N : Integer;
begin
N := len;
SetLength(Result,N * 2 + 1);
BinToHex(PChar(A),PChar(Result),N);
end;


procedure TMainFrm.BtnSendClick(Sender: TObject);
var
tmp:array[0..1024] of char;
i,Count:integer;
str:string;
List:TList;
begin
if IdTCPServer.Active then
begin
str:= trim(EdtSend.Text);
if str='' then
begin
showmessage('不能为空!');
EdtSend.SetFocus;
Exit;
end;

try
if not ChkSndHex.Checked then
begin
strpcopy(tmp,str);
List := IdTCPServer.Threads.LockList; //取得所有客户列表
try
for Count := 0 to List.Count -1 do //遍历所有客户
try
TIdPeerThread(List.Items[Count]).Connection.WriteBuffer(tmp,length(str)); //向客户写字符串
except
TIdPeerThread(List.Items[Count]).Stop;
end;
finally
IdTCPServer.Threads.UnlockList;
end;
end
else
begin
if (length(str) mod 2)<>0 then
begin
showmessage('位数必须为偶数');
exit;
end
else
begin
FillChar(tmp,sizeof(tmp),#0);
for i:=0 to (length(str) div 2-1) do
begin
try
tmp:= char( strtoint('$'+ Copy(str,i*2+1,2)));
except
showmessage('格式不对!请查证!');
EdtSend.SetFocus;
Exit;
end;
end;
List := IdTCPServer.Threads.LockList; //取得所有客户列表
try
for Count := 0 to List.Count -1 do //遍历所有客户
try
TIdPeerThread(List.Items[Count]).Connection.WriteBuffer(tmp,length(str) div 2); //向客户写字符串
except
TIdPeerThread(List.Items[Count]).Stop;
end;
finally
IdTCPServer.Threads.UnlockList;
end;
end;
end;
except

end;
end
else
begin
showmessage('端口还没有打开');
end;

end;






procedure TMainFrm.BtnAboutClick(Sender: TObject);
begin
showmessage('端口监听工具'+#10#13+'Design by Gigi!'+#13#10+'EMail:soulmate_gigi@163.com!');
end;

procedure TMainFrm.BtnClearClick(Sender: TObject);
begin
Meo_Rec.Clear;
end;

procedure TMainFrm.FormCreate(Sender: TObject);
begin
BtnStop.Enabled :=false;
end;

end.
 
顶到找出办法~^o^
 
自己在INDY控件中加入KEEPALIVE属性就可以了!
如果不用INDY的话就给套接字中加入KEEPALIVE属性就可以了!
 
fxh7622,不太明白你说的意思~可否详细解释一下~
我用的就是Indy Server控件,传统的TServer Tclient控件没有这个问题~
Indy Server没有你说的这个KeepALive属性啊?
要加,应该怎么样做,还希望能说详细些~
 
你在INDY中手动加一下(不知道INDY有没有,好像indy的TCP Server是没有的)。
你跟一下,看INDY中的TCP Server调用函数BIND的时候。你加一下就可以了!
我们这边就是这样解决的。
不错如果做网络开发建议你使用API函数。我们公司以前也使用INDY后来发现INDY有很多限制,并且修改不易。所以现在改用API了!
如果不知道怎么设置KEEPALIVE的话,问我就可以了!我尽量帮助你吧!
 
定时发链路检测包,并更新客户端的活动时间,超时的为吊线
 
Indy Server没有这个属性~
 
在INTCPSERVER.PAS文件中,你找SETACTIVE函数。在这里加入KEEPALIVE数据就可以了!
skyccf:
你说的方法是一个通用方法。说起来可以但是实现起来很不容易。
1:TCP是一个面向连接的协议,本身就有请求、回答过程。你自己要实现这么很不容易。
2:KEEPALIVE属性就是提供了检测包的能力(也就心跳数据包)。允许你设置每个心跳的时间(例如1秒钟发送多少个心跳包)。并且检测及时。
 
此属性需要自己加入!
 
我在看看~
 
fxh7662
我在SetActive函数的

SetSockOpt(Id_SOL_SOCKET, Id_SO_REUSEADDR, PChar(@Id_SO_True), SizeOf(Id_SO_True));后面增加了

SetSockOpt(Id_SOL_SOCKET, Id_SO_KEEPALIVE, PChar(@Id_SO_True), SizeOf(Id_SO_True));
还是不行啊~我理解是设置了KeepAlive为True。
对这里不太懂啊~帮忙在看看有哪里错了~
 
呵呵,你写的有问题了!
 
所说看啊~哪里有问题~
 
不是简单的将KeepAlive设置为TRUE就可以了。设置的时候需要指定你想让心跳包多长时间发送一次。需要定义一个结构!你加我的QQ吧,我在那里给你说!
 
你的qq是多少啊?
 
我的是513479626
 
加了~兄弟~换了个技术qq~^o^ 都是陕西的啊~
 
呵呵!是呀,我也是陕西的!
 
后退
顶部