IdTCPServerExecute работи, но не получава данни

Аз съм много нов в delphi и имам два проекта, написани на delphi, които трябва да комуникират - клиент и сървър. успях да накарам комуникациите да работят за свързване и прекъсване, но не мога да накарам клиента да изпраща съобщения до сървъра с натискане на бутон - изглежда, че съобщенията не стигат до сървъра.

ето кода на клиента:

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 на сървъра. може би не го използвам правилно или може би трябва да настроя някои параметри, преди да използвам тази процедура?


person mulllhausen    schedule 16.05.2013    source източник
comment
Какъв порт отваряте? Знаете ли, че не е със защитна стена?   -  person J...    schedule 16.05.2013
comment
Защитната стена блокира връзките, а не данните. ОП каза, че връзката е успешна. Така че проблемът не е в защитната стена.   -  person Remy Lebeau    schedule 16.05.2013
comment
@RemyLebeau да, прав си, разбира се; хубаво.   -  person J...    schedule 17.05.2013


Отговори (1)


Вашият сървърен код извиква IOHandler.ReadLn(), който очаква (CR)LF след текста. Вашият клиент се обажда на IOHandler.Write(), който не изпраща (CR)LF. Вместо това клиентът трябва да извика IOHandler.WriteLn().

person Remy Lebeau    schedule 16.05.2013
comment
отлично. използвах sLineBreak според този въпрос и отговор - person mulllhausen; 17.05.2013
comment
sLineBreak е зависим от платформата. Това е CRLF на Windows, но е LF на други платформи. Наистина не трябва да го използвате за комуникация. Просто използвайте WriteLn(), както казах: ` IOHandler.WriteLn(txtData.Text). It always sends a CRLF. If you insist on using Write(), then at least use Indy's own EOL` вместо това, което е CRLF на всички платформи: IOHandler.Write(txtData.Text+EOL) - person Remy Lebeau; 17.05.2013
comment
трябваше да прочета отговора ти по-внимателно, пропуснах това. Благодаря отново. - person mulllhausen; 17.05.2013
comment
Изморих се да изпълнявам този проект, сървърът стартира нормално на порт 801, но когато бутонът за свързване на клиента щракна, той показва това съобщение: attempting to connect to ip [127.0.0.1:801] и след 2 секунди cannot connect to ip [127.0.0.1:801], какво може да причини това? - person peiman F.; 14.03.2014
comment
Сървърът работи ли на същата машина като клиента? Проверихте ли с netstat или друг инструмент, че сървърът действително слуша 127.0.0.1:801? - person Remy Lebeau; 14.03.2014
comment
да, и двете са на една и съща машина, но няма слушател на 801 порт!! как мога да оправя сървъра?! качих своя клиентски и сървърен код тук: http://nilzoom.com/codes/p2p.rar - person peiman F.; 15.03.2014
comment
@peimanF.: Проверете два пъти свойството Port на всеки запис в колекцията Bindings на сървъра. Вие настройвате DefaultPort на сървъра динамично, но ако Bindings не е празно, тогава промяната на DefaultPort не актуализира Port на съществуващите Bindings записи. Трябва или да ги актуализирате поотделно, или Clear Bindings, така че сървърът да може да ги създаде отново, когато се активират. Когато активирате сървъра, трябва да преминете през Bindings регистрирането на всеки IP/порт, който действително се използва. - person Remy Lebeau; 15.03.2014
comment
@peimanF.: Освен това във вашите сървърни манипулатори на събития не е безопасно за нишки да се извиква директно lbLog.Items.Add(). Трябва да синхронизирате с основната нишка, като например чрез TThread.Synchronize(), TThread.Queue(), TIdSync или TIdNotify, за безопасен достъп до потребителския интерфейс, в противен случай могат да се случат лоши неща, включително блокирания и сривове. Освен това във вашия OnExecute манипулатор се отървете от CheckForDataOnSource() и InputBufferIsEmpty(). Обадете се на ReadLn() безусловно и го оставете да блокира, докато пристигнат данни или настъпи прекъсване на връзката. - person Remy Lebeau; 15.03.2014
comment
благодаря ти remy, добавих нов въпрос тук: https://stackoverflow.com/questions/22422694/delphi-idtcpserver-not-listening - person peiman F.; 15.03.2014