delphi - 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
现在有两个问题
- TIdUDPClient 没有类似 onread/onreceiver 事件;
- 从 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 连续发回数据。简单的。但不起作用。
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.
解决方案
推荐阅读
- php - CakePHP Querybuilder 和计数语法
- meteor - {{#if currentUser}} 用户注销时仍会呈现内部图标
- python - Python - 访问字典中的所有属性
- azure-devops - Azure DevOps API 源管理 - 设置源权限不起作用
- azure-sql-database - Azure 逻辑应用内部服务器错误 500
- mysql - 学习Inner join multitable时发现SQL查询报错
- google-maps - 为什么 turfjs 距离返回的结果与 Google Map 几何库 computeDistanceBetween 不同?
- jenkins - 无法将参数从一个管道作业传递到另一个
- reactjs - 如何更改 React 地图中的渲染顺序
- tfs - 功能的 TFS 查询未“完成”,但所有子用户故事都“完成”