Ich versuche, einen Stream von einem mobilen Gerät (iOS, Android) an TCP-Server zu senden. Für die Server- und Client-Seite verwende ich die Indy-Komponenten.TIdiOHandler.Write-Prozedur funktioniert nicht von mobilen Geräten
Das Problem tritt auf, wenn ich versuche, einen Stream von einer FMX-Anwendung auf einem mobilen Gerät zu senden. Wenn ich den Client-Code von Windows ausführe, sendet der Client den Stream an die Server-App. Aber ich benutze denselben Code von einem mobilen Gerät, der Stream wird nicht gesendet.
Dies ist ein minimales, vollständiges und überprüfbares Beispiel für den Server und den Client, mit dem das Problem reproduziert werden kann.
Serverseite. Der Server ist eine VCL Anwendung.
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.
Client (FMX Anwendung)
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.
Die Frage ist: Wie kann ich einen Stream mit der Indy-Komponente von einem mobilen Gerät senden ?.
UPDATE:
Android Berechtigungen
<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" />
Haben Sie die entsprechenden Berechtigungen für den Netzzugang in der mobilen Anwendung Manifeste haben? –
Ich habe gerade die Berechtigungen hinzugefügt. – Salvador