求多线程思路(200分)

  • 主题发起人 主题发起人 yjpya
  • 开始时间 开始时间
Y

yjpya

Unregistered / Unconfirmed
GUEST, unregistred user!
各位朋友,请看以下两个Unit的代码,两段代码的原来功能分别一个是负责接收信息,一个负责发送信息,请问,假如我想实现类似PcAnyWhere的监控功能,下面的两段代码该如何修改?即代码二的程序作为Server端,代码一的程序也作为Client端,Client端在启动的时候就不停向Server端发出数据包,Server端可以获得所有Client发送过来的数据包,而且知道哪些Client是在线的?请各位朋友赐教,多谢!!!

代码一:
unit pop;
interface
uses
Unit2,
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdThreadMgr, IdThreadMgrDefault, StdCtrls, IdBaseComponent,
IdComponent, IdTCPServer;
type
PClient = ^TClient;
TClient = record // Object holding data of client (see events)
CIP,
DNS : String[20];
{ Hostname }
Connected, { Time of connect }
LastAction : TDateTime;
{ Time of last transaction }
Thread : Pointer;
{ Pointer to thread }
end;

type
TForm1 = class(TForm)
Server: TIdTCPServer;
Memo1: TMemo;
IdThreadMgrDefault1: TIdThreadMgrDefault;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject;
var Action: TCloseAction);
procedure ServerConnect(AThread: TIdPeerThread);
procedure ServerDisconnect(AThread: TIdPeerThread);
procedure ServerExecute(AThread: TIdPeerThread);
private
RecMsg: string;
procedure ShowMsg;
public
end;

var
Form1: TForm1;
Clients: TThreadList;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
Clients := TThreadList.Create;
Server.Active :=True;
end;

procedure TForm1.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
Server.Active := False;
Clients.Free;
end;

procedure TForm1.ServerConnect(AThread: TIdPeerThread);
var //连接时自动建立一个线程Athread
NewClient: PClient;
begin
GetMem(NewClient, SizeOf(TClient));
//申请内存
NewClient.CIP := ATHread.Connection.Socket.Binding.PeerIP;
NewClient.DNS := NewClient.CIP;
NewClient.Connected := Now;
NewClient.LastAction := NewClient.Connected;
NewClient.Thread := AThread;
AThread.Data:=TObject(NewClient);
try
Clients.LockList.Add(NewClient);
//加入到全局变量:clients列表线程列表中
finally
Clients.UnlockList;
end;
end;

procedure TForm1.ServerDisconnect(AThread: TIdPeerThread);
var //Athread为断开的那个连接对应的线程
ActClient: PClient;

begin
ActClient := PClient(AThread.Data);
try
Clients.LockList.Remove(ActClient);
finally
Clients.UnlockList;
end;
FreeMem(ActClient);
AThread.Data := nil;
end;

procedure TForm1.ServerExecute(AThread: TIdPeerThread);
var //client端发送数据过来 即执行
CommBlock, NewCommBlock: TCommBlock;//server端和client端传递的数据结构TCommBlock
begin
if not AThread.Terminated and AThread.Connection.Connected then
begin
AThread.Connection.ReadBuffer (CommBlock, SizeOf (CommBlock));
recmsg:='From:'+CommBlock.CIp+#13+'Message:'+CommBlock.Msg;
// RecMsg := Format('From: %s, Msg: %s, Cmd: %d',[CommBlock.CIp,CommBlock.Msg,CommBlock.Command]);
AThread.Synchronize(ShowMsg);
if CommBlock.Command = 1 then
begin
NewCommBlock.Command := 0;
NewCommBlock.Msg := '收到命令'+inttostr(CommBlock.Command)+':'+CommBlock.Msg;
//do anything
end
else
// unknown command given
begin
NewCommBlock.Command := -1;
NewCommBlock.Msg := 'Ido
n''t understand your command: "'
+inttostr(CommBlock.Command)+'"';
end;
AThread.Connection.WriteBuffer (NewCommBlock, SizeOf (NewCommBlock),true);
end;
end;

procedure TForm1.ShowMsg;
begin
Memo1.Lines.Add(RecMsg);
end;

end.

代码二:
unit send;

interface
uses
Unit2,
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
StdCtrls;
type
TClientHandleThread = class(TThread)
private
CB: TCommBlock;
procedure HandleInput;
protected
procedure Execute;
override;
end;

type
TForm1 = class(TForm)
btnSend: TButton;
Memo1: TMemo;
edtIPAddr: TEdit;
Client: TIdTCPClient;
procedure btnSendClick(Sender: TObject);
private
procedure SendMsg(Msg: string);
public
{ Public declarations }
end;

var
Form1: TForm1;
ClientHandleThread: TClientHandleThread;

implementation
{$R *.dfm}
{ TClientHandleThread }
procedure TClientHandleThread.Execute;
begin
inherited;
while not Terminateddo
//线程执行部分 永远不停的执行
begin
if not Form1.Client.Connected then
Terminate
else
try
Form1.Client.ReadBuffer(CB, SizeOf (CB));
//将idtcpclient接收到的消息读入到线程对象的CB块
Synchronize(HandleInput);
//解析消息执行动作
if (cb.command=0) or (cb.command=-1) then
Terminate;
except
// null exceptions...
end;
end;
end;

procedure TClientHandleThread.HandleInput;
begin
Form1.Client.Disconnect;
if cb.command=0 then
showmessage('发送成功。'+cb.Msg)
else
if cb.command=-1 then
showmessage('发送失败。'+cb.Msg)
else
showmessage('未知返回值');
end;

{ TForm1 }
procedure TForm1.SendMsg(Msg: string);
var
CommBlock : TCommBlock;
begin
if not client.Connected then
try
client.Host:=edtIPAddr.Text;
Client.Connect(10000);
// in Indy < 8.1 leave the parameter away
ClientHandleThread := TClientHandleThread.Create(True);//开启客户端 启动全局线程
ClientHandleThread.FreeOnTerminate:=True;
ClientHandleThread.Resume;
// assign the data that's should be sended
CommBlock.Command := 1;

CommBlock.CIp := Client.Socket.Binding.IP;
CommBlock.CHost:= Client.LocalName;
CommBlock.Msg := Msg;
Client.WriteBuffer(CommBlock, SizeOf (CommBlock), true);
//发送数据
except
on E: Exceptiondo
begin
MessageDlg ('连接服务器失败:'+#13+E.Message+#13+'请检查服务器是否正常运行',
mtError, [mbOk], 0);
exit;
end;
end
else
showmessage('上一次向服务器请求的命令还未完成,请稍等');
end;

procedure TForm1.btnSendClick(Sender: TObject);
begin
SendMsg(Memo1.Lines.Text);
end;

end.
 
哥儿们,谁有那么多时间,一点一点看你的代码啊
只说说思路应该还可以
 
二楼的朋友,能告诉一个思路吗?请告知,多谢!!!!
 
服务器端启动一个UDP接收端口
客户端周期性的向服务器发送UDP包
这个UDP包中可以含有希望知道的数据
这样就可以很简单的
发送的时候可以使用队列,将要发送的内容排列
 
楼上的大虾,具体怎样实现呢?有没相关的例子呢?
 
解决问题的思路:
在SERVER端对所有联接的CLIENT建立一个数据结构,

TClientData Packed Record
IP:String;
Port:WOrd;
Flags:Integer
end
Flags存放一个整数,我一般定为5
客户端有一个线程,每隔10秒或你不定时的发,但间隔时间不要超过服务器设定时间*Flags,比如说你比较忙的时候,可以长一点再发,网络比较忙时,可以隔一段时间再发等,由程序而定、对服务器发一个keepalive包,这个包可以比较短一点,甚至是一个字节(最好加一个时间,或增大的流水号,防止有人编程对你的SERVERdo
S)。
服务器收到这个keep alive包后,就判断,如果是5则不变,如果小于5,则加一次。(这里注意同步)。
服务端有一个线程,每15秒对于所有的TClientData这样扫描一次,每扫描一次,把Flags-1,如果发现这个Flags数值=0了,就对IP:Port发送一次退出指令(不管收不收得到),同时把这个结构体清除,表示不在线了。也就是说,如果客户端15*5秒(时间可以改的啦)=45秒没有与服务器联系的话,表示离线。
用DELPHI里的线程可以解决这些问题,但是要注意同步,因为两个线程都要读的数是共享区,因此你要建立一个标志。当然可以放在Record里面。这是后话。
 
这个用C与S控件,如
在S端广播一个包说:“你们哪些在线,在线的站出来!” 网卡地址为(FFFFFFFF)
在C端听到这个包说:“我在这儿,你给我怎么搞!”(发送一个响应包到服务器端)
然后服务器端就可以接管了!
具体代码www.delphibox.com上有!!!
 
楼上的朋友,高高高,但DelphiBox哪一个例子是对应的源码呢?请赐教,多谢!!!
 
我来接分了,散吧
 
想通了,结贴!!!
 
请楼主详细说一下思路,最好把代码给发上 来看看,谢谢
 
后退
顶部