我正在尝试将流从移动设备(iOS,Android)发送到TCP Server.对于服务器和客户端,我正在使用Indy组件.
当我尝试从移动设备中运行的FMX应用程序发送流时,会发生此问题.如果我从Windows运行客户端代码,则客户端会将流发送到Server App.但是我从移动设备上运行了相同的代码,但未发送流.
这是服务器和客户端的最小,完整和可验证的示例,可以重现此问题.
服务器端 .该服务器是VCL应用程序.
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) 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.
客户端(FMX应用程序)
unit uClient;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, FMX.ScrollBox,
FMX.Memo, FMX.Controls.Presentation, FMX.StdCtrls;
type
TFrmClient = class(TForm)
IdTCPClient1: TIdTCPClient;
Button1: TButton;
MemoLog: TMemo;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
procedure Send;
public
{ Public declarations }
end;
var
FrmClient: TFrmClient;
implementation
{$R *.fmx}
type
TSendThread = class(TThread)
private
FTCPClient : TIdTCPClient;
public
procedure Execute; override;
constructor Create(ATCPClient : TIdTCPClient); reintroduce;
end;
procedure TFrmClient.Button1Click(Sender: TObject);
begin
Send;
end;
procedure TFrmClient.FormCreate(Sender: TObject);
begin
try
IdTCPClient1.Port := 28888;
IdTCPClient1.Host := '192.168.1.134'; //change this to the ip of the TCP server.
IdTCPClient1.ConnectTimeout := 5000;
IdTCPClient1.Connect();
MemoLog.Lines.Add('Connected');
except on E: Exception do
MemoLog.Lines.Add('Exception ' + E.Message);
end;
end;
procedure TFrmClient.Send;
begin
if IdTCPClient1.Connected then
TSendThread.Create(IdTCPClient1);
end;
{ TSendThread }
constructor TSendThread.Create(ATCPClient: TIdTCPClient);
begin
inherited Create(False);
FTCPClient := ATCPClient;
end;
procedure TSendThread.Execute;
var
LStream : TStream;
d : Int64;
begin
LStream := TMemoryStream.Create;
try
//Send a text from all the platforms works perfect.
FTCPClient.IOHandler.WriteLn('');
LStream.Size := 1024;
LStream.Position := 0;
d := LStream.Size;
FTCPClient.IOHandler.LargeStream := True;
//this only works from Windows
FTCPClient.IOHandler.Write(LStream, d, True);
finally
LStream.Free;
end;
end;
end.
问题是,如何使用Indy组件从移动设备发送流?
更新:
Android权限
解决方法:
最终,我发现了这个问题,我误以为没有发送数据,发送了流,但是服务器无法处理流,因为TIdIOHandler.ReadStream函数无法正确读取流的大小.在AByteCount参数中传递-1值时,会发生这种情况.然后,使用TIdIOHandler.ReadInt64或TIdIOHandler.ReadInt32函数读取流的大小,并且在内部,这些函数试图使用GStack.NetworkToHost函数转换整数的字节序.
我解决了读取流大小而不转换字节序的问题.
我替换了这条线
LHandler.ReadStream(LMemoryStream, -1, False);
对于此代码
LHandler.LargeStream := True;
LHandler.ReadBytes(LBytes, SizeOf(Int64), False);
d := BytesToInt64(LBytes);
LHandler.ReadStream(LMemoryStream, d, False);
标签:delphi-10-1-berlin,ios,android,delphi
来源: https://codeday.me/bug/20191112/2023937.html