Delphi 中的 ClientSocket 错误

Error with ClientSocket in Delphi

您好,我对以下代码有疑问:

program client;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils, System.Win.ScktComp, idContext, idGlobal;

var
  ClientSocket1: TClientSocket;
  m: TMethod;
  m2: TMethod;

procedure hi(Sender: TObject; Socket: TCustomWinSocket);
begin
  ClientSocket1.Socket.SendText('hello');
  Writeln('connect');
end;

Procedure read_data(Sender: TObject; Socket: TCustomWinSocket);
Var
  Raw: String;
Begin
  Raw := Socket.ReceiveText;
  Writeln(Raw);
End;

begin
  try

    ClientSocket1 := TClientSocket.Create(nil);
    ClientSocket1.Address := '127.0.0.1';
    ClientSocket1.Port := 123;
    ClientSocket1.Open;

    m.Code := @read_data;
    m.Data := ClientSocket1;
    ClientSocket1.OnRead := TSocketNotifyEvent(m);

    m2.Code := @hi;
    m2.Data := ClientSocket1;
    ClientSocket1.OnConnect := TSocketNotifyEvent(m2);

    while '1' = '1' do
    begin
      //
    end;

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;

end.

问题是未从服务器接收到任何信息,并且在正确连接后未在程序中检测到。 该程序是一个控制台应用程序,使用 ClientSocket 组件进行连接。

服务器程序在图形应用程序中 运行 并使用启用了端口 123 的 ServerSocket 组件,使用这些按钮:

procedure TForm1.Button1Click(Sender: TObject);
begin
  ServerSocket1.Socket.Connections[ListBox1.Itemindex].SendText(Edit1.Text);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  lugar: Integer;
begin
  ListBox1.Clear;
  for lugar := 0 To ServerSocket1.Socket.ActiveConnections - 1 do
  begin
    ListBox1.Items.add(ServerSocket1.Socket.Connections[lugar].RemoteHost);
  end;
end;

有人可以帮助我吗?

默认情况下,TClientSocket 以非阻塞模式运行。在该模式下,它在内部使用 window 消息来触发其事件。但是你的代码中没有消息循环,所以你需要添加一个。您也没有正确设置事件处理程序(您缺少显式 Self 参数,因为您的处理程序不是 class 的成员)。

试试这个:

program client;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, System.Win.ScktComp, Winapi.Windows;

procedure socket_connected(Self: Pointer; Sender: TObject; Socket: TCustomWinSocket);
begin
  Writeln('connect');
  Socket.SendText('hello');
end;

procedure socket_disconnected(Self: Pointer; Sender: TObject; Socket: TCustomWinSocket);
begin
  Writeln('disconnect');
  PostQuitMessage(0);
end;

procedure socket_read(Self: Pointer; Sender: TObject; Socket: TCustomWinSocket);
var
  Raw: String;
begin
  Raw := Socket.ReceiveText;
  Writeln(Raw);
end;

procedure socket_error(Self: Pointer; Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer);
begin
  Writeln('error');
  PostQuitMessage(0);
end;

var
  ClientSocket1: TClientSocket;
  m: TMethod;
  msg: TMsg;
begin
  try
    ClientSocket1 := TClientSocket.Create(nil);
    try
        ClientSocket1.Address := '127.0.0.1';
        ClientSocket1.Port := 123;

        m.Code := @socket_connected;
        m.Data := ClientSocket1;
        ClientSocket1.OnConnect := TSocketNotifyEvent(m);

        m.Code := @socket_disconnected;
        m.Data := ClientSocket1;
        ClientSocket1.OnDisconnect := TSocketNotifyEvent(m);

        m.Code := @socket_read;
        m.Data := ClientSocket1;
        ClientSocket1.OnRead := TSocketNotifyEvent(m);

        m.Code := @socket_error;
        m.Data := ClientSocket1;
        ClientSocket1.OnError := TSocketErrorEvent(m);

        ClientSocket1.Open;

        while GetMessage(msg, 0, 0, 0) do
        begin
          TranslateMessage(msg);
          DispatchMessage(msg);
        end;
      finally
        ClientSocket1.Free;
      end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;    
end.

否则,将套接字更改为阻塞模式,并完全摆脱事件处理程序:

program client;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, System.Win.ScktComp;

var
  ClientSocket1: TClientSocket;
  Raw: String;
begin
  try
    ClientSocket1 := TClientSocket.Create(nil);
    try
        ClientSocket1.Address := '127.0.0.1';
        ClientSocket1.Port := 123;
        ClientSocket1.ClientType := ctBlocking;

        try
          ClientSocket1.Open;
          Writeln('connect');
          ClientSocket1.Socket.SendText('hello');
          repeat
            Raw := ClientSocket1.Socket.ReceiveText;
            if Raw <> '' then Writeln(Raw);
          until not ClientSocket1.Connected;
          Writeln('disconnect');
        except    
          Writeln('error');
          raise;
        end;
      finally
        ClientSocket1.Free;
      end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;    
end.