The android-tidiohandler.write procedure cannot be run on a mobile device

I am trying to send streams from mobile devices (IOS, Android) to TCP server. For server and client, I am using Indy component

This problem occurs when I try to send a stream from an FMX application running on my mobile device. If I run client code from windows, the client will send the stream to the server app. However, I run the same code from my mobile device, but did not send the stream

This is a minimal, complete and verifiable example of the server and client that can reproduce this problem

Server side. This server is a VCL application

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 application)

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.Scroll@R_188_2419@,
  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.

The question is, how do I send a stream from a mobile device using the Indy component?

to update:

Android permissions

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

resolvent:

Finally, I found this problem. I mistakenly thought that no data was sent and the stream was sent, but the server could not process the stream, because the tidiohandler.readstream function could not correctly read the stream size. This happens when passing the - 1 value in the abytecount parameter. Then, use the tidiohandler.readint64 or tidiohandler.readint32 function to read the stream size, and internally, These functions attempt to convert the byte order of integers using the gstack. Networktohost function

I solved the problem of reading stream size without converting byte order

I replaced this line

LHandler.ReadStream(LMemoryStream, -1, False);

For this code

LHandler.LargeStream := True;
LHandler.ReadBytes(LBytes, SizeOf(Int64), False);
d := BytesToInt64(LBytes);
LHandler.ReadStream(LMemoryStream, d, False);

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>