Android TIdIOHandler。写入过程在移动设备上不起作用
我正在尝试从移动设备(iOS、Android)向TCP服务器发送流。对于服务器端和客户端,我使用Indy组件 当我试图从移动设备上运行的FMX应用程序发送流时,就会出现问题。如果我从Windows运行客户端代码,客户端会将流发送到服务器应用程序。但是我在一个移动设备上运行了相同的代码,流没有被发送 对于服务器和客户端来说,这是一个最小、完整且可验证的示例,可以重现问题 服务器端。服务器是一个VCL应用程序Android TIdIOHandler。写入过程在移动设备上不起作用,android,ios,delphi,delphi-10.1-berlin,Android,Ios,Delphi,Delphi 10.1 Berlin,我正在尝试从移动设备(iOS、Android)向TCP服务器发送流。对于服务器端和客户端,我使用Indy组件 当我试图从移动设备上运行的FMX应用程序发送流时,就会出现问题。如果我从Windows运行客户端代码,客户端会将流发送到服务器应用程序。但是我在一个移动设备上运行了相同的代码,流没有被发送 对于服务器和客户端来说,这是一个最小、完整且可验证的示例,可以重现问题 服务器端。服务器是一个VCL应用程序 unit uServer; interface uses Winapi.Windo
unit uServer;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IdBaseComponent, IdComponent,
IdCustomTCPServer, IdTCPServer, Vcl.StdCtrls, IdContext;
type
TFrmServer = class(TForm)
IdTCPServer1: TIdTCPServer;
MemoLog: TMemo;
procedure FormCreate(Sender: TObject);
procedure IdTCPServer1Execute(AContext: TIdContext);
private
{ Private declarations }
public
{ Public declarations }
end;
var
FrmServer: TFrmServer;
implementation
uses
IdGlobal,
IdIOHandler,
System.StrUtils;
{$R *.dfm}
procedure TFrmServer.FormCreate(Sender: TObject);
begin
IdTCPServer1.Bindings.Clear;
IdTCPServer1.DefaultPort := 28888;
IdTCPServer1.Active := True;
MemoLog.Lines.Add('Running');
end;
procedure TFrmServer.IdTCPServer1Execute(AContext: TIdContext);
var
LHandler : TIdIOHandler;
s: string;
LMemoryStream : TMemoryStream;
AFormatSettings: TFormatSettings;
d : Int64;
begin
try
LHandler := AContext.Connection.IOHandler;
s := LHandler.ReadLn(LF, IdTimeoutDefault, MaxInt);
AFormatSettings := TFormatSettings.Create;
if (s <> '') then
begin
if StartsText('<', s) and EndsText('>', s) then
begin
TThread.Queue(nil,
procedure
begin
MemoLog.Lines.Add(Format('%s', [s], AFormatSettings));
end
);
LMemoryStream := TMemoryStream.Create;
try
LHandler.LargeStream := True;
LHandler.ReadStream(LMemoryStream, -1, False);
d := LMemoryStream.Size;
TThread.Queue(nil,
procedure
begin
MemoLog.Lines.Add(Format('Stream Size %d', [d], AFormatSettings));
end
);
finally
LMemoryStream.Free;
end;
end
else
LHandler.InputBuffer.Clear;
end;
except
on E: Exception do
begin
s := E.Message;
TThread.Queue(nil,
procedure
begin
MemoLog.Lines.Add(Format('Exception %s', [s], AFormatSettings));
end
);
end;
end;
end;
end.
unituserver;
接口
使用
Winapi.Windows、Winapi.Messages、System.SysUtils、System.Variants、System.Classes、Vcl.Graphics、,
控件、窗体、对话框、IdBaseComponent、IdComponent、,
IdCustomTCPServer、IdTCPServer、Vcl.StdCtrls、IdContext;
类型
TFrmServer=class(TForm)
IdTCPServer1:TIdTCPServer;
备忘录:TMemo;
过程表单创建(发送方:ToObject);
过程IdTCPServer1Execute(AContext:TIdContext);
私有的
{私有声明}
公众的
{公开声明}
结束;
变量
FrmServer:TFrmServer;
实施
使用
IdGlobal,
白痴汉德勒,
系统结构;
{$R*.dfm}
过程TFrmServer.FormCreate(发送方:TObject);
开始
IdTCPServer1.Bindings.Clear;
IdTCPServer1.DefaultPort:=28888;
IdTCPServer1.Active:=True;
MemoLog.Lines.Add('Running');
结束;
过程TFrmServer.IdTCPServer1Execute(AContext:TIdContext);
变量
LHandler:TIdIOHandler;
s:字符串;
LMemoryStream:TMemoryStream;
a格式设置:t格式设置;
d:Int64;
开始
尝试
LHandler:=AContext.Connection.IOHandler;
s:=LHandler.ReadLn(LF,IdTimeoutDefault,MaxInt);
a格式设置:=t格式设置。创建;
如果是“”,则
开始
如果开始文本(“”,s),则
开始
TThread.Queue(nil,
程序
开始
添加(格式('%s',[s],格式设置));
结束
);
LMemoryStream:=TMemoryStream.Create;
尝试
LHandler.LargeStream:=True;
ReadStream(LMemoryStream,-1,False);
d:=LMemoryStream.尺寸;
TThread.Queue(nil,
程序
开始
MemoLog.Lines.Add(格式('流大小%d',[d],格式设置));
结束
);
最后
自由流;
结束;
结束
其他的
LHandler.InputBuffer.Clear;
结束;
除了
关于E:Exception-do
开始
s:=E.消息;
TThread.Queue(nil,
程序
开始
MemoLog.Lines.Add(格式('Exception%s',[s],aformSettings));
结束
);
结束;
结束;
结束;
结束。
客户端(FMX应用程序)
单元客户端;
接口
使用
System.SysUtils、System.TYPE、System.UITYPE、System.Classes、System.VARIANT、,
FMX.类型,FMX.控件,FMX.窗体,FMX.图形,FMX.对话框,
IdBaseComponent、IdComponent、IdTCPConnection、IdTCPClient、FMX.ScrollBox、,
FMX.Memo,FMX.Controls.Presentation,FMX.StdCtrls;
类型
TFrmClient=class(TForm)
IdTCPClient1:tidtcplient;
按钮1:t按钮;
备忘录:TMemo;
过程表单创建(发送方:ToObject);
程序按钮1点击(发送方:ToObject);
私有的
程序发送;
公众的
{公开声明}
结束;
变量
FRM客户:TFrmClient;
实施
{$R*.fmx}
类型
TSendThread=class(TThread)
私有的
FTCPClient:TIdTCPClient;
公众的
程序执行;推翻
构造函数创建(ATCPClient:TIdTCPClient);重新引入;
结束;
程序TFrmClient.Button1Click(发件人:ToObject);
开始
发送;
结束;
过程TFrmClient.FormCreate(发送方:TObject);
开始
尝试
IdTCPClient1.端口:=28888;
IdTCPClient1.Host:=“192.168.1.134”//将此更改为TCP服务器的ip。
IdTCPClient1.ConnectTimeout:=5000;
IdTCPClient1.Connect();
MemoLog.Lines.Add('Connected');
E上除外:例外
MemoLog.Lines.Add('Exception'+E.Message);
结束;
结束;
程序TFrmClient.Send;
开始
如果IdTCPClient1.已连接,则
创建(IdTCPClient1);
结束;
{TSendThread}
构造函数TSendThread.Create(ATCPClient:TIdTCPClient);
开始
继承创建(False);
FTCPClient:=ATCPClient;
结束;
程序TSendThread.Execute;
变量
1流:TStream;
d:Int64;
开始
LStream:=TMemoryStream.Create;
尝试
//发送来自所有平台的文本非常完美。
FTCPClient.IOHandler.WriteLn(“”);
l流大小:=1024;
1流位置:=0;
d:=L流尺寸;
FTCPClient.IOHandler.LargeStream:=True;
//这只能在Windows上工作
FTCPClient.IOHandler.Write(LStream,d,True);
最后
自由流;
结束;
结束;
结束。
问题是,如何使用Indy组件从移动设备发送流
更新:
Android权限
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Indy在所有平台上的运行方式都相同,因此流的发送或接收方式应该没有区别 我在代码中看到的唯一问题是:
InputBuffer的不必要调用。在服务器代码中清除
3C 48 65 6C 6C 6F 3E 0D 0A 00 00 00 00 00 00 04 00
后跟1024字节的随机数据(因为您没有用任何有意义的数据填充TMemoryStream
)
也就是说,在本例中,您实际上不需要将d
传递给TIdIOHandler.Write(TStream)
的ASize
参数。你可以通过-1
3C 48 65 6C 6C 6F 3E 0D 0A 00 00 00 00 00 00 04 00
LHandler.ReadStream(LMemoryStream, -1, False);
LHandler.LargeStream := True;
LHandler.ReadBytes(LBytes, SizeOf(Int64), False);
d := BytesToInt64(LBytes);
LHandler.ReadStream(LMemoryStream, d, False);