RTC Forums
November 24, 2024, 04:03:30 AM *
Welcome, Guest. Please login or register.

Login with username, password and session length
 
   Home   Help Login Register  
Pages: [1]
  Print  
Author Topic: Consule App not responding  (Read 5214 times)
jeff.lott
RTC Expired
*
Posts: 11


« on: December 03, 2015, 05:49:30 PM »

Using RTC v715, Delpi XE10
Have a project group with two projects.

project 1, win64, is form + RTCRestModule (datamodule) which has rtc components and code.
form creates datamodule, form click button does RTCRestModule.RtcHttpServer1.Listen();
browser does GET and application responds with JSON data as expected
TRtcHttpServer and TRtcDataProvider events fire and work as expected

project 2, win64, is consule app + same exact RTCRestModule  datamodule.
the "start" command does RTCRestModule.RtcHttpServer1.Listen(); (just like form)
TRtcHttpServer.OnListenStart fires as expected
browser does same GET request and hangs
No TRtcHttpServer and TRtcDataProvider events are fired.

What am I missing? Thanks, Jeff

TRtcHttpServer  has Multitreaded set to false


Code:
=========================
program rtcRESTserverConsuleApp;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  RTCWebRestUnit in 'RTCWebRestUnit.pas' {RTCRestModule: TDataModule};

procedure LogMessage(Msg: String);
begin
  WriteLn(Msg);
end;

var
  Command, ExePath, ConsoleAppName, RootDir: String;

begin
  try
    Command := '';
    ExePath := ParamStr(0);
    ConsoleAppName := ChangeFileExt(ExtractFileName(ExePath), '');
    RootDir := ExtractFileDir(ExePath);
    WriteLn(ConsoleAppName);
    RTCRestModule := TRTCRestModule.Create(nil);
    RTCRestModule.LogMessage := LogMessage;

    WriteLn('Waiting for command: Start, Exit');
    while True do begin
      if (Command = '') then
        ReadLn(Command);

      if (CompareText(Command, 'Exit') = 0) then begin
        if RTCRestModule.RtcHttpServer1.isListening then
          RTCRestModule.RtcHttpServer1.StopListen;
        Break;
      end;

      if (CompareText(Command, 'Start') = 0) then begin
        Command := '';
        RTCRestModule.RtcHttpServer1.Listen();
      end;

    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  FreeAndNil(RTCRestModule);

end.
=====================================
unit RESTserver_form;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;

type
  TRESTserverForm = class(TForm)
    Panel1: TPanel;
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  RESTserverForm: TRESTserverForm;

implementation

{$R *.dfm}

uses RTCWebRestUnit;

procedure LogMessage(Msg: String);
begin
  RESTserverForm.Memo1.Lines.Add(Msg);
end;

procedure TRESTserverForm.Button1Click(Sender: TObject);
begin
  LogMessage('START');
  RTCRestModule.RtcHttpServer1.Listen();
end;

procedure TRESTserverForm.Button2Click(Sender: TObject);
begin
  RTCRestModule.RtcHttpServer1.StopListen;
end;

procedure TRESTserverForm.FormCreate(Sender: TObject);
begin
  RTCRestModule := TRTCRestModule.Create(nil);
  RTCRestModule.LogMessage := LogMessage;
end;

procedure TRESTserverForm.FormDestroy(Sender: TObject);
begin
  FreeAndNil(RTCRestModule);
end;

end.
=====================================
unit RTCWebRestUnit;

interface

uses
  System.SysUtils, System.Classes, WinApi.Windows,
  rtcActiveX, rtcConn, rtcDataSrv, rtcHttpSrv, rtcInfo;

type
  TLogMessageNotifyEvent = procedure(Msg: String);
  TRTCRestModule = class(TDataModule)
    Controller_Ping: TRtcDataProvider;
    RtcHttpServer1: TRtcHttpServer;
    Controller_Favicon: TRtcDataProvider;
    procedure RtcHttpServer1ListenStart(Sender: TRtcConnection);
    procedure Controller_PingCheckRequest(Sender: TRtcConnection);
    procedure Controller_PingDataReceived(Sender: TRtcConnection);
    procedure RtcHttpServer1Connect(Sender: TRtcConnection);
    procedure RtcHttpServer1RequestNotAccepted(Sender: TRtcConnection);
    procedure RtcHttpServer1ClientConnect(Sender: TRtcConnection);
    procedure RtcHttpServer1ListenStop(Sender: TRtcConnection);
    procedure Controller_FaviconCheckRequest(Sender: TRtcConnection);
    procedure Controller_FaviconDataReceived(Sender: TRtcConnection);
  private
    { Private declarations }
  public
    { Public declarations }
    LogMessage: TLogMessageNotifyEvent;
  end;

var
  RTCRestModule: TRTCRestModule;

implementation

{%CLASSGROUP 'Vcl.Controls.TControl'}

{$R *.dfm}

procedure TRTCRestModule.Controller_FaviconDataReceived(Sender: TRtcConnection);
var
  Srv:TRtcDataServer absolute Sender;
  RootDir, ExePath, FileName: String;
  f: THandle;
  size, sRead: Int64;
  Buffer: RtcByteArray;
begin
  if Srv.Request.Complete then begin
    Srv.Response.ContentType := 'image/x-icon';
    ExePath := ParamStr(0);
    RootDir := ExtractFileDir(ExePath);
    FileName := RootDir+'\favicon.ico';
    if (FileExists(FileName) = true) then begin
      f := FileOpen(FileName, fmOpenRead+fmShareDenyNone);
      if (f = INVALID_HANDLE_VALUE) then begin
        Srv.Response.Status(404,'File not found');
        Write('Status 404: File not found');
        Exit;
      end;
      Try
        size := FileSeek(f,int64(0),2); // 2 = The file pointer is positioned Offset bytes from the end of the file
        Srv.Response.ContentLength := size;
        SetLength(Buffer,Size);
        FileSeek(f,int64(0),int64(0));
        sRead := FileRead(f,Buffer[0],Size);
        if sRead<Size
          then SetLength(Buffer,sRead);
        Srv.Write(RtcBytesToString(Buffer));
      Finally
        FileClose(f);
      End;
    end else
      Srv.Write;
  end;
end;

procedure TRTCRestModule.Controller_PingCheckRequest(Sender: TRtcConnection);
var
  Srv:TRtcDataServer absolute Sender;
begin
  if (CompareText(Srv.Request.FileName, '/Ping') = 0) then
    Srv.Accept;
end;

procedure TRTCRestModule.Controller_PingDataReceived(Sender: TRtcConnection);
var
  Srv:TRtcDataServer absolute Sender;
  Result: TRtcRecord;
begin
  if Srv.Request.Complete then begin
    Result:=TRtcRecord.Create;
    Try
      Result.asBoolean['successful'] := true;
      Result.asText['message'] := 'OK';
      Result.asDateTime['Time'] := Now;
      Srv.WriteEx(Result.toJSONEx);
    Finally
      FreeAndNil(Result);
    End;
  end;
end;

procedure TRTCRestModule.Controller_FaviconCheckRequest(Sender: TRtcConnection);
var
  Srv:TRtcDataServer absolute Sender;
begin
  if (CompareText(Srv.Request.FileName, '/favicon.ico') = 0) then
    Srv.Accept;
end;

procedure TRTCRestModule.RtcHttpServer1ClientConnect(Sender: TRtcConnection);
begin
  LogMessage('Server.OnClientConnect');
end;

procedure TRTCRestModule.RtcHttpServer1Connect(Sender: TRtcConnection);
begin
  LogMessage('Server.OnConnect');
end;

procedure TRTCRestModule.RtcHttpServer1ListenStart(Sender: TRtcConnection);
begin
  if not Sender.inMainThread then
    Sender.Sync(RtcHttpServer1ListenStart)
  else begin
    LogMessage('Server is Listening on Port '+Sender.LocalPort);
    LogMessage('TreadID: ' + IntToStr(GetCurrentThreadId));
  end;
end;

procedure TRTCRestModule.RtcHttpServer1ListenStop(Sender: TRtcConnection);
begin
  if not Sender.inMainThread then
    Sender.Sync(RtcHttpServer1ListenStop)
  else begin
    LogMessage('Server Stopped Listening');
  end;
end;

procedure TRTCRestModule.RtcHttpServer1RequestNotAccepted(Sender: TRtcConnection);
var
  Srv:TRtcDataServer absolute Sender;
begin
  LogMessage('Server.RequestNotAccepted: ' + Srv.Request.FileName);
end;

end.
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #1 on: December 03, 2015, 05:54:40 PM »

Console applications do not have a message queue, which is required for single-threaded async WinSock (used by default). To use RTC Server components in console Applications, you need to set the MultiThreaded property to TRUE, which creates a background thread with a message queue for handling messages. The same is true for Windows Service Applications.

For Client Applications, it would be enough to set the Blocking, useProxy or useWinHTTP property to TRUE, which would use Blocking WinSock, blocking WinInet or WinHTTP. But that doesn't work for a Server, which has to handle more than one connection.

Best Regards,
Danijel Tkalcec
Logged
jeff.lott
RTC Expired
*
Posts: 11


« Reply #2 on: December 03, 2015, 06:04:49 PM »

Originally I had MultiThreading set to true, but had this problem:

OnListenStart fires with (not Sender.inMainThread = true) so Sender.Sync(RtcHttpServer1ListenStart) executes as expected.
But RtcHttpServer1ListenStart is never called a 2nd time, and does not respond to browser requests.

FYI, when I have this working I plan to create a windows service version of the application.

procedure TRTCRestModule.RtcHttpServer1ListenStart(Sender: TRtcConnection);
begin
  if not Sender.inMainThread then
    Sender.Sync(RtcHttpServer1ListenStart)
  else begin
    LogMessage('Server is Listening on Port '+Sender.LocalPort);
    LogMessage('TreadID: ' + IntToStr(GetCurrentThreadId));
  end;
end;
Logged
D.Tkalcec (RTC)
Administrator
*****
Posts: 1881


« Reply #3 on: December 03, 2015, 06:18:24 PM »

The Sync method does not work in Console Applications, because Console Applications do not have a message queue in the Main Thread. If you need your Server to run as a Console Application, you have to use the TRtcHttpServer component with MultiThreaded=True, write thread-safe code and forget about the "Sync" method.

Best Regards,
Danijel Tkalcec
Logged
jeff.lott
RTC Expired
*
Posts: 11


« Reply #4 on: December 03, 2015, 07:52:24 PM »

Got it. Thanks!
It's working nicely now.
Logged
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!
Page created in 0.026 seconds with 16 queries.