2013-05-16 59 views
2

我對delphi很新,我有兩個用delphi編寫的必須通信的項目 - 一個客戶端和一個服務器。我已經設法得到連接和斷開連接的通信,但是我無法讓客戶端通過單擊按鈕向服務器發送消息 - 看起來消息不會將其發送到服務器。IdTCPServerExecute運行,但沒有收到數據

這裏是客戶端代碼:

unit my_client; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, StdCtrls, IdAntiFreezeBase, IdAntiFreeze, IdTCPConnection, 
    IdTCPClient, IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, 
    IdBaseComponent, IdComponent; 

type 
    TForm1 = class(TForm) 
    lstLog: TListBox; 
    Label1: TLabel; 
    txtData: TEdit; 
    Label2: TLabel; 
    Label3: TLabel; 
    Label4: TLabel; 
    txtServer: TEdit; 
    txtPort: TEdit; 
    btnConnect: TButton; 
    btnSend: TButton; 
    btnDisconnect: TButton; 
    IdAntiFreeze1: TIdAntiFreeze; 
    Client: TIdTCPClient; 
    procedure btnConnectClick(Sender: TObject); 
    procedure btnSendClick(Sender: TObject); 
    procedure btnDisconnectClick(Sender: TObject); 
    private 
    ip: string; 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.btnConnectClick(Sender: TObject); 
begin 
    Client.Host := txtServer.Text; 
    Client.Port := StrToInt(txtPort.Text); 
    ip := txtServer.Text + ':' + txtPort.Text; 
    lstLog.Items.Add('attempting to connect to ip [' + ip + ']'); 
    with Client do 
    begin 
     try //try connecting 
      Connect; 
      lstLog.Items.Add('successfully connected to ip [' + ip + ']'); 
      try //try getting data 
      lstLog.Items.Add('response: [' + Client.IOHandler.ReadLn() + ']'); 
      BtnConnect.Enabled := False; 
      BtnSend.Enabled := True; 
      btnDisconnect.Enabled := True; 
      except 
      lstLog.Items.Add('cannot send data to ip [' + ip + ']'); 
      Client.Disconnect(); 
      end; //end try getting data 
     except 
      lstLog.Items.Add('cannot connect to ip [' + ip + ']'); 
     end; //end try connecting 
    end; //end with 
end; //end begin 

procedure TForm1.btnSendClick(Sender: TObject); 
begin 
    lstLog.Items.Add('sending data: [' + txtData.Text + ']...'); 
    with Client do 
    begin 
    try 
     IOHandler.Write(txtData.Text); 
     lstLog.Items.Add('sent data: [' + txtData.Text + ']'); 
    except 
     lstLog.Items.Add('failed to send data [' + ip + ']'); 
     Client.Disconnect(); 
     lstLog.Items.Add('Disconnect with ' + txtServer.Text + ' !'); 
     BtnConnect.Enabled := True; 
     BtnSend.Enabled := False; 
     btnDisconnect.Enabled := False; 
    end;//end try 
    end;//end with 
end; 

procedure TForm1.btnDisconnectClick(Sender: TObject); 
begin 
    Client.Disconnect(); 
    lstLog.Items.Add('disconnected from ip [' + ip + ']'); 
    BtnConnect.Enabled := True; 
    BtnSend.Enabled := False; 
    btnDisconnect.Enabled := False; 
end; 

end. 

,這裏是我的服務器代碼:

unit my_server; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, StdCtrls, IdTCPConnection, IdTCPClient, IdBaseComponent, 
    IdComponent, IdCustomTCPServer, IdTCPServer, IdContext, IdThread, IdSync; 

type 
    TfrmTCPServer = class(TForm) 
    edtPort: TEdit; 
    Label1: TLabel; 
    Label2: TLabel; 
    lbLog: TListBox; 
    btnStart: TButton; 
    btnStop: TButton; 
    IdTCPServer: TIdTCPServer; 
    procedure btnStartClick(Sender: TObject); 
    procedure btnStopClick(Sender: TObject); 
    procedure IdTCPServerConnect(AContext: TIdContext); 
    procedure IdTCPServerExecute(AContext: TIdContext); 
    procedure IdTCPServerDisconnect(AContext: TIdContext); 
    procedure IdTCPServerException(AContext: TIdContext; 
     AException: Exception); 
    private 
    { Private declarations } 
    public 
    end; 
var 
    frmTCPServer: TfrmTCPServer; 

implementation 

uses 
    StrUtils; 

{$R *.dfm} 

procedure TfrmTCPServer.btnStartClick(Sender: TObject); 
begin 
    IdTCPServer.DefaultPort := StrToInt(EdtPort.Text); 
    IdTCPServer.Active := True; 
    BtnStart.Enabled := False; //don't let it be clicked again 
    BtnStop.Enabled := True; //let it be clicked again 
    lbLog.Items.Add('server started'); 
end; 

procedure TfrmTCPServer.btnStopClick(Sender: TObject); 
begin 
    if IdTCPServer.Active = true then 
    begin 
    IdTCPServer.Active := False; 
    BtnStart.Enabled := True; //let it be clicked now 
    BtnStop.Enabled := False; //don't let it be clicked again 
    lbLog.Items.Add('server stopped'); 
    end 
    else 
    begin 
    lbLog.Items.Add('server already stopped'); 
    end 
end; 

procedure TfrmTCPServer.IdTCPServerConnect(AContext: TIdContext); 
begin 
    try 
    AContext.Connection.IOHandler.WriteLn('100: welcome to tcp test server'); 
    lbLog.Items.Add('server received connection from [' + Acontext.Connection.Socket.Binding.PeerIP + ']'); 
    except 
    lbLog.Items.Add('got here2'); 
    end; 
end; 

procedure TfrmTCPServer.IdTCPServerExecute(AContext: TIdContext); //this is looped infinitely? 
var 
    client_data: string; //strCommand 
begin 
    with AContext.Connection do 
    begin 
    IOHandler.CheckForDataOnSource(10); 
    if not IOHandler.InputBufferIsEmpty then 
    begin 
     client_data := IOHandler.ReadLn(); 
     IOHandler.WriteLn('received data [' + client_data + ']'); 
     lbLog.Items.Add('received data [' + client_data + '] from ' + Socket.Binding.PeerIP); 
    end; //end if 
    end; //end with 
end; 

procedure TfrmTCPServer.IdTCPServerDisconnect(AContext: TIdContext); 
begin 
    lbLog.Items.Add('client at ip [' + Acontext.Connection.Socket.Binding.PeerIP + '] has disconnected'); 
end; 

procedure TfrmTCPServer.IdTCPServerException(AContext: TIdContext; 
    AException: Exception); 
begin 
    lbLog.Items.Add('server exception: [' + AException.Message + ']'); 
end; 

end. 

的問題似乎在於服務器上的IdTCPServerExecute程序英寸也許我沒有正確使用它,或者我可能需要在使用此過程之前設置一些參數?

+0

你打開哪個港口?你知道這不是防火牆嗎? –

+2

防火牆阻止連接,而不是數據。 OP表示連接成功。所以這不是防火牆問題。 –

+0

@RemyLebeau是的,你說得對,當然;不錯。 –

回答

4

您的服務器代碼正在調用IOHandler.ReadLn(),該文本在文本之後需要一個(CR)LF。您的客戶呼叫IOHandler.Write(),它不發送(CR)LF。客戶需要撥打IOHandler.WriteLn()來代替。

+0

優秀。我使用sLineBreak根據[這個q&a](http://stackoverflow.com/questions/254407) – mulllhausen

+0

'sLineBreak'是平臺相關的。它是Windows上的CRLF,但在其他平臺上是LF。你真的不應該使用它進行通信。只需使用'WriteLn()'就像我說的:'IOHandler.WriteLn(txtData.Text)'。它總是發送一個CRLF。如果你堅持使用Write(),那麼至少應該使用Indy自己的'EOL',這是所有平臺上的CRLF:'IOHandler.Write(txtData.Text + EOL)' –

+0

我應該看過你的答案更仔細,我錯過了。再次感謝。 – mulllhausen