首页 > 解决方案 > Delphi、Indy TIdUDPServer 和从 TIdUDPClient 读取

问题描述

你好亲爱的社区。

我有 :

应用程序 A;是我的应用程序,在同一端口上有一个 UDP 客户端和服务器。
应用程序 B;这是我无法控制的:它是 Laminar Research 的 XPlane 11.50(它工作得很好,用 WireShark 和其他工具验证了这个海豚)。

让我们假设遵循这个时间线:

0 App A 开始使用 IdUDPServer 监听端口 49000。
1 App A向App B请求(发送缓冲区)请求发送数据(IdUDPCLient端口49000)并自行关闭;
2 应用程序 B 开始发送其数据,直到应用程序 A 停止它,就像在时间 1 一样。(但是我的 UDP 服务器端口没有任何东西,Wireshark 检测到数据!!!)。
3 App A 关闭 IdUTPServer 和 IUdpClient。

在浪费了数百行代码尝试之后,我终于意识到问题在于需要立即重用客户端套接字以从 XPlane 监听。所以所有的通信都必须通过 UDP 客户端完成。

我正在使用德尔福 10.3

现在有两个问题

  1. TIdUDPClient 没有类似 onread/onreceiver 事件;
  2. 从 UDP 客户端读取有两种方法: ReceiveBuffer()/ReceiveString() 由于接收数据是字节数组(因此也是 ASCII <32)字符串不是最好的方法,但是如果我使用 ReceiveBuffer 并且错误会引发并说“Socket Error #10040 Message Too Long”。

问:我怎样才能得到一个没有错误的缓冲区?有没有办法在数据进入时触发 UDPCLient 中的事件?

谢谢你从这个头痛中解脱...

这是引发错误的如此小的来源

Var Loc_Array,Loc_Back_Array:TIdBytes;
    i:integer;
    s:string
begin
   if not Indi_Client.Active then begin
     Show_FeedBack(LB_CLIENT_FEEDBACK, 'Can not send ... Client Disables ');
     Exit;
   end;
   try
     if (Sender=XP_STOP)  then Loc_Array := [ 82, 80, 79, 83, 0, 48, 0 ];
     if (Sender=XP_START) then Loc_Array := [ 82, 80, 79, 83, 0, 49, 0 ];
     if Indi_Client.Active then begin
       Indi_Client.SendBuffer( Loc_Array);
       Show_FeedBack(LB_CLIENT_FEEDBACK,'Send '+Bytes_Values(Loc_Array)+'->' +BytesToString(Loc_Array));
       //
       // here raise the error 10040
       //
       Indi_Client.ReceiveBuffer(Loc_Back_Array);
       //
       s:=Indi_Client.ReceiveString();
     end;
   finally
     if Indi_Client.Active
        then LBL_CLIENT_FEEDBACK.Caption:='Active '+DateTimeToStr(Now)
        else LBL_CLIENT_FEEDBACK.Caption:='Paused ...';
   end;
end;

这里是我写的最新和最干净的代码来尝试它,因此 Remis 建议(据我所知)XPlane 收到一个启动触发器,然后他在端口 49000 上从请求来自的同一 IP 连续发回数据。简单的。但不起作用。

![XPlane发送1后的反馈]

type
  TMain_Form = class(TForm)
    ListBox1: TListBox;
    BTN_START: TButton;
    Indi_Server: TIdUDPServer;
    BTN_STOP: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Indi_ServerUDPRead(AThread: TIdUDPListenerThread; const AData: TIdBytes; ABinding: TIdSocketHandle);
    procedure BTN_STARTClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Main_Form: TMain_Form;
  Receiving,
  XPlane_Start_Sending,
  XPlane_Stop_Sending: TIdBytes;


implementation

{$R *.dfm}

procedure TMain_Form.BTN_STARTClick(Sender: TObject);
Const IP_Dest_1:string = '192.168.1.64';
      IP_Dest_2:string = '127.0.0.1';
begin
     if Indi_Server.Active then begin
       Beep; // a debug bell
       Indi_Server.Active:=False;
     end;
     // You can send this as many as you want
     if (Sender=BTN_START) then begin
       Indi_Server.SendBuffer( IP_Dest_1, 49010, Id_IPv4, XPlane_Start_Sending );
     //Indi_Server.SendBuffer( IP_Dest_2, 49010, Id_IPv4, XPlane_Start_Sending );
     end;
     if (Sender=BTN_STOP) then begin
       Indi_Server.SendBuffer( IP_Dest_1, 49010, Id_IPv4, XPlane_Stop_Sending );
     //Indi_Server.SendBuffer( IP_Dest_2, 49010, Id_IPv4, XPlane_Stop_Sending );
     end;
end;

procedure TMain_Form.FormCreate(Sender: TObject);
begin
     XPlane_Stop_Sending  := [ 82, 80, 79, 83, 0, 48,  0]; // 0 stop sending (zero item per second)
     XPlane_Start_Sending := [ 82, 80, 79, 83, 0, 49, 48,  0]; // 10 items per second
     //
     with Indi_Server do begin // as dropper onto the form from the palette
       DefaultPort:=49000;
       ReuseSocket:=TIdReuseSocket.rsTrue;
     end;
end;

procedure TMain_Form.Indi_ServerUDPRead(AThread: TIdUDPListenerThread; const AData: TIdBytes; ABinding: TIdSocketHandle);
var i:Integer;
    s:string;
begin
     ListBox1.Items.Clear;
     Receiving:=AData;
     ListBox1.Items.Add( BytesToString(Receiving) );
     ListBox1.Items.Add( BytesToString(AData) );
     for i:=Low(Receiving) to High(Receiving) do begin
       s:=s+Receiving[i].ToString+'  ';
     end;
     ListBox1.Items.Add(s);
     ListBox1.Items.Add('-------------------------');
end;

end.

标签: delphiserverudpclientindy

解决方案


推荐阅读