2014-04-26 111 views
0

我花了一段時間編寫一個簡單的應用程序來在TIdTCPServerTIdTCPClient之間交換數據。但現在我卡住了。
我可以將數據從TIdTCPClient發送到TIdTCPServer並且可以處理這個。
但是不知道和官方文檔沒有給出任何線索如何發送TIdTCPServer的數據並在TIdTCPClient上處理它。請指教。Indy TIdTCPServer TIdTCPClient數據交換

我的代碼很簡單:

主要應用:

var 
    Form1: TForm1; 

implementation 

uses ClientThread, ServerThread; 

var 
    ClientThread: TClientThread; 
    ServerThread: TServerThread; 

{$R *.fmx} 

procedure TForm1.Button1Click(Sender: TObject); 
var OutputDebugString:string; 
begin 
    ServerThread:=TServerThread.Create(False); 
    ServerThread.Priority:=tpNormal; 
end; 

procedure TForm1.Button2Click(Sender: TObject); 
begin 
    ClientThread:=TClientThread.Create(False); 
    ClientThread.Priority:=tpNormal; 
end; 

服務器線程:

unit ServerThread; 

interface 

uses 
    Classes, System.SysUtils, IdContext, IdTCPServer, TaskQue; 

type 
    TServerThread = class(TThread) //MyThread - заданное нами имя потока. 
    private 
    { Private declarations } 
    protected 
    procedure Execute; override; 
    end; 

TServer = class(TObject) 
    IdTCPServer1: TIdTCPServer; 
    procedure IdTCPServer1Execute(AContext: TIdContext); 
    procedure IdTCPServer1Connect(AContext: TIdContext); 
    private 
    { Private declarations } 
    constructor Create; 
    public 
    end; 

type 
TDatagram = record 
    Proto: byte; 
    Command: word; 
    DataSize: word; 
    data: array [0..4096] of byte; 
    end; 

var 
    Server : TServer; 

implementation 

uses YouFreedom; 

constructor TServer.Create; 
begin 
inherited Create; 
IdTCPServer1 := TIdTCPServer.Create(nil); 
IdTCPServer1.Bindings.Clear; 
// IdTCPServer1.DefaultPort := 10001; 
    try 
    with idTCPserver1.Bindings.Add do 
    begin 
     IP := '127.0.0.1'; 
     Port := 10001; 
    end; 
    finally  //dirty hack 
     idTCPserver1.Bindings.Add.IP := '127.0.0.1'; 
     idTCPserver1.Bindings.Add.Port := 10002; 
    end; 
// idTCPserver1.Bindings.Add.Port:=10001; 
// IdTCPServer1.Bindings.Add.IP := '127.0.0.1'; 
IdTCPServer1.Tag := 0; 
IdTCPServer1.TerminateWaitTime := 5000; 
IdTCPServer1.OnConnect := IdTCPServer1Connect; 
IdTCPServer1.OnExecute := IdTCPServer1Execute; 
end; 

procedure TServer.IdTCPServer1Execute(AContext: TIdContext); 

var 
    MIRec: TDatagram; 
    msRecInfo: TMemoryStream; 
    size: integer; 
    i:integer; 
    recieve:byte; 
    respstream: TMemoryStream; 
begin 
    try 
    msRecInfo:= TMemoryStream.Create; 
    AContext.Connection.IOHandler.ReadStream(msRecInfo, -1, false); 
    msRecInfo.Position := 0; 
    msRecInfo.ReadBuffer(MIRec, msRecInfo.size); 
    Form1.addtoque := '1'; 
// Form1.s := inttostr(MIRec.Proto) 
    Form1.Memo1.Lines.Add('Proto = ' + inttostr(MIRec.Proto)); 
    finally 
    msRecInfo.Free 
    end; 
end; 

procedure TServer.IdTCPServer1Connect(AContext: TIdContext); 
begin 
//AContext.Connection.Socket.WriteLn('hello'); 
end; 

procedure TServerThread.Execute; 
begin 
Server := TServer.Create; 
try 
    Server.IdTCPServer1.Active := True; 
except 
     on E: Exception do 
     // OutputDebugString(PChar(E.ToString)); //do something 
     end; 
end; 


end. 

客戶端線程:

unit ClientThread; 

interface 

uses 
    Classes, IdTCPClient; 

type 
    TClientThread = class(TThread) //MyThread - заданное нами имя потока. 
    private 
    { Private declarations } 
    protected 
    procedure Execute; override; 
    end; 

TClient = class(TObject) 
    IdTCPClient1: TIdTCPClient; 
// procedure IdTCPClient1OnWorkBegin(AContext: TIdContext); 
    private 
    { Private declarations } 
    constructor Create; 
    public 
    end; 

implementation 

type 
TDatagram = record 
    Proto: byte; 
    Command: word; 
    DataSize: word; 
    data: array [0..4096] of byte; 
    end; 

var 
    ClientConnection : TClient; 

constructor TClient.Create; 
begin 
inherited Create; 
IdTCPClient1 := TIdTCPClient.Create(nil); 
// IdTCPClient1.ReuseSocket := rsOSDependent; 
IdTCPClient1.Host := '127.0.0.1'; 
IdTCPClient1.Port := 10001; 
// IdTCPClient1.OnWorkBegin := IdTCPClient1OnWorkBegin; 
end; 

procedure TClientThread.Execute; 
var 
    MIRec: TDatagram; 
    msRecInfo: TMemoryStream; 
    i,k:integer; 
    Client1: TIdTCPClient; 
    recieve:byte; 
    respstream: TMemoryStream; 
begin 
    ClientConnection := TClient.Create; 
    ClientConnection.IdTCPClient1.Connect; 
    for k := 1 to 5 do begin 

    if ClientConnection.IdTCPClient1.Connected then begin 
{ MIRec.DataSize := 64; 
    for i:=0 to MIRec.DataSize do 
    MIRec.data[i] := i; 
    for i:=129 to 4096 do MIRec.data[i] := 0;} 
    MIRec.Proto := 1; 
    MIRec.Command :=1; 
    try 
    msRecInfo := TMemoryStream.Create; 
    msRecInfo.WriteBuffer(MIRec, SizeOf(MIRec)); 
    msRecInfo.Position := 0; 
    ClientConnection.IdTCPClient1.IOHandler.Write(msRecInfo, msRecInfo.Size, true); 
    finally 
    msRecInfo.Free; 
    end; 
    end; 
    end 
end; 




end. 

回答

3

您濫用Bindings.Add()和週四s的創建綁定:

127.0.0.1:10001 
127.0.0.1:0 
0.0.0.0:10002 

我敢肯定,是不是你真正想要的東西。

至於你的問題 - 這取決於你的服務器需要做什麼。

如果服務器只有響應客戶端命令,那麼您可以在讀取命令後直接在OnExecute事件中寫入響應。客戶端可以在發送命令後立即讀取響應。這是典型的用法。

如果服務器只有主動發送數據給客戶,那麼你就可以在需要時Lock()服務器的Contexts列表中,找到所需的連接和寫入,然後Unlock()列表。客戶必須閱讀這些消息,以異步方式讀取,如在線程中。

如果服務器需要做,那麼這會變得棘手。最好的選擇是爲每個客戶端實現一個線程安全的出站隊列,然後您可以將未經請求的數據放入隊列中,並在隊列安全的情況下發送隊列的內容OnExecute

我之前曾多次在Embarcadero和Indy論壇上發佈過所有這些實例。到處搜索。

+0

這段代碼只是一個原型,所以我沒有太在意安全和資源管理。你是對的最後我想要一個que來回答客戶異步的方式。並停留在服務器和客戶端的事件發送數據回客戶端。不過,我會嘗試搜索。 – user3576941