gpt4 book ai didi

android - TIdIOHandler.Write 程序不适用于移动设备

转载 作者:太空宇宙 更新时间:2023-11-03 13:46:46 28 4
gpt4 key购买 nike

我正在尝试从移动设备(iOS、Android)向 TCP 服务器发送流。对于服务器端和客户端,我使用的是 Indy 组件。

当我尝试从移动设备中运行的 FMX 应用程序发送流时​​,会出现此问题。如果我从 Windows 运行客户端代码,客户端会将流发送到服务器应用程序。但是我从移动设备运行相同的代码,但没有发送流。

这是服务器和客户端的最小、完整且可验证的示例,可以重现问题。

服务器端。服务器是一个 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) 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.

客户端(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('<Hello>');
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 组件从移动设备发送流?

更新:

安卓权限

<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" />

最佳答案

终于找到问题了,我误以为数据没有发送,流发送了,但是服务器无法处理流,因为 TIdIOHandler.ReadStream 函数没有正确读取流的大小。当在 AByteCount 参数中传递 -1 值时会发生这种情况。然后 TIdIOHandler.ReadInt64TIdIOHandler.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);

关于android - TIdIOHandler.Write 程序不适用于移动设备,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40851329/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com