2014-04-26 9 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()와 목을 오용하는 나는 그것이 당신이 정말로 원하는 것을하지 확신

127.0.0.1:10001 
127.0.0.1:0 
0.0.0.0:10002 

:들 바인딩을 만들 수 있습니다.

귀하의 질문은 - 서버가 수행해야하는 작업에 따라 다릅니다.

만 클라이언트 명령에 응답하면 명령을 읽은 후 OnExecute 이벤트에 직접 응답을 쓸 수 있습니다. 클라이언트는 명령을 보낸 직후 응답을 읽을 수 있습니다. 이것은 일반적인 사용법입니다. 서버 클라이언트에 원치 않는 데이터를 전송하는 경우

는, 당신은 필요로 할 때, 서버의 Contexts 목록을 Lock() 원하는 연결을 찾아, 그것을 다음 Unlock() 목록을 작성할 수 있습니다. 클라이언트는 이러한 메시지를 읽기 위해 스레드와 같이 비동기 적으로 읽어야합니다.

서버가 모두 일 필요가 있으면이 작업이 까다로워집니다. 가장 좋은 방법은 각 클라이언트에 대해 스레드 안전 아웃 바운드 대기열을 구현 한 다음 원치 않는 데이터를 대기열에 넣고 안전 할 때 대기열의 내용을 OnExecute에 보낼 수 있습니다.

나는이 모든 예를 여러 번 전에 Embarcadero 및 Indy 포럼에 게시했습니다. 주변을 검색하십시오.

+0

이 코드는 단지 프로토 타입이므로 안전 및 리소스 관리에 너무 많은주의를 기울였습니다. 그리고 당신은 마침내 나는 클라이언트가 비동기 적으로 응답 할 수 있기를 바란다. 그리고 서버와 클라이언트 측 모두에서 이벤트를 클라이언트에 다시 보내야합니다. 그러나 나는 검색하려고 노력할 것이다. – user3576941