Recent

Author Topic: Trying, and failing, to create a TCP Client  (Read 1909 times)

Thausand

  • Sr. Member
  • ****
  • Posts: 405
Re: Trying, and failing, to create a TCP Client
« Reply #15 on: September 06, 2025, 12:29:09 pm »
However, I found that this works:
Is suggest: Not smart is shift network address because depend order. There FPC function for help https://www.freepascal.org/docs-html/rtl/sockets/strtohostaddr.html Have also look below other function and what do.

geraldholdsworth

  • Sr. Member
  • ****
  • Posts: 265
Re: Trying, and failing, to create a TCP Client
« Reply #16 on: September 06, 2025, 12:40:42 pm »
Is suggest: Not smart is shift network address because depend order. There FPC function for help https://www.freepascal.org/docs-html/rtl/sockets/strtohostaddr.html Have also look below other function and what do.
Cheers - I did find that function afterwards. I just took the code direct from the example and modified it. I've been looking at what other functions the socket unit contains.

geraldholdsworth

  • Sr. Member
  • ****
  • Posts: 265
Re: Trying, and failing, to create a TCP Client
« Reply #17 on: September 06, 2025, 02:29:45 pm »
I noticed in that code, which was an exmaple for 'fpConnect' did not feature 'fpConnect', but the depreciated 'Connect'. So, I've played around and got this working:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. uses Sockets, SysUtils;
  4.  
  5. Var
  6.   SAddr    : TInetSockAddr;
  7.   Buffer   : string [255];
  8.   input    : String;
  9.   S        : Longint;
  10.   i,j      : integer;
  11.  
  12. begin
  13.  S:=fpSocket(AF_INET,SOCK_STREAM,0);
  14.  if s<>-1 then
  15.  begin
  16.   SAddr.sin_family:=AF_INET;
  17.   SAddr.sin_port:=HtoNS(23);
  18.   SAddr.sin_addr.s_addr:=HostToNet(192<<24 or 168<<16 or 210);
  19. //  SAddr.sin_addr.s_addr:=StrToHostAddr('192.168.0.210').s_addr;
  20.   WriteLn('Connecting...');
  21.   if fpConnect(S,@SAddr,SizeOf(SAddr))=0 then
  22.   begin
  23.    //Get the initial response
  24.    i:=fpRecv(S,@Buffer,SizeOf(Buffer),0);
  25.    if i>0 then
  26.    begin
  27.     input:='';
  28.     for j:=0 to i do input:=input+Buffer[j];
  29.     WriteLn(input);
  30.    end;
  31.    //Send a query
  32.    input:='wG40000AU'#$0D#$0A;
  33.    StrPCopy(@Buffer,input);
  34.    fpSend(S,@Buffer,Length(input),0);
  35.    //Reset the buffer
  36.    StrPCopy(@Buffer,StringOfChar(#0,255));
  37.    //And get the response
  38.    i:=fpRecv(S,@Buffer,SizeOf(Buffer),0);
  39.    if i>0 then
  40.    begin
  41.     input:='';
  42.     for j:=0 to i do input:=input+Buffer[j];
  43.     WriteLn(input);
  44.    end;
  45.   end;
  46.  end;
  47. end.
However, note the commented out line - if I uncomment this (and comment the first), it hangs while trying to connect. Any ideas?

(incidentally, I haven't done too much working with pointers)
« Last Edit: September 06, 2025, 02:32:17 pm by geraldholdsworth »

Wallaby

  • Full Member
  • ***
  • Posts: 113
Re: Trying, and failing, to create a TCP Client
« Reply #18 on: September 06, 2025, 02:44:16 pm »
Quote
However, note the commented out line - if I uncomment this (and comment the first), it hangs while trying to connect. Any ideas?

Use StrToNetAddr, you need the bytes to be in the network byte order (Big Endian) while StrToHostAddr would return them in the host byte order (Little Endian).

geraldholdsworth

  • Sr. Member
  • ****
  • Posts: 265
Re: Trying, and failing, to create a TCP Client
« Reply #19 on: September 06, 2025, 03:26:47 pm »
Perfect. Thank you.

geraldholdsworth

  • Sr. Member
  • ****
  • Posts: 265
Re: Trying, and failing, to create a TCP Client
« Reply #20 on: September 07, 2025, 01:04:39 pm »
OK. That was short lived.
Got the program communicating absolutely fine as a command line program. But, as soon as I stick the same code into a GUI application (I rewrote it as a class, then used the exact same class, no changes), it then refuses to connect.
This is definately Apple's doing...
 >:(

Thaddy

  • Hero Member
  • *****
  • Posts: 18363
  • Here stood a man who saw the Elbe and jumped it.
Re: Trying, and failing, to create a TCP Client
« Reply #21 on: September 07, 2025, 01:50:13 pm »
Or Pears for that matter, or Strawberries..
Show us what you did?
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

geraldholdsworth

  • Sr. Member
  • ****
  • Posts: 265
Re: Trying, and failing, to create a TCP Client
« Reply #22 on: September 07, 2025, 02:05:30 pm »
This is the code, put into a class and tested succesfully in a console program:
Code: Pascal  [Select][+][-]
  1. unit TCPClient;
  2.  
  3. {$MODE objfpc}{$H+}{$M+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes,SysUtils,Sockets;
  9.  
  10. type
  11.   TTCPClient = class
  12.   private
  13.    FSocket : LongInt;
  14.   public
  15.    Constructor Create;
  16.    Destructor Destroy; override;
  17.    function IsConnected: Boolean;
  18.    function GetLastError: String;
  19.   published
  20.    procedure Connect(IP: String; Port: Integer);
  21.    procedure Disconnect;
  22.    function Receive: String;
  23.    procedure Send(Output: String);
  24.    property Connected : Boolean read IsConnected;
  25.    property LastError : String read GetLastError;
  26. end;
  27.  
  28. implementation
  29.  
  30. { TTCPClient }
  31.  
  32. {-------------------------------------------------------------------------------
  33. Creates the class
  34. -------------------------------------------------------------------------------}
  35. constructor TTCPClient.Create;
  36. begin
  37.  inherited Create;
  38.  FSocket:=-1;
  39. end;
  40.  
  41. {-------------------------------------------------------------------------------
  42. Are we connected to a server?
  43. -------------------------------------------------------------------------------}
  44. function TTCPClient.IsConnected: Boolean;
  45. begin
  46.  Result:=FSocket<>-1;
  47. end;
  48.  
  49. {-------------------------------------------------------------------------------
  50. What was the last error reported?
  51. -------------------------------------------------------------------------------}
  52. function TTCPClient.GetLastError: String;
  53. begin
  54.  Result:='Unknown error ('+IntToStr(socketerror)+')';
  55.  case socketerror of
  56.   EsockADDRINUSE      : Result:='Socket address is already in use';
  57.   EsockEACCESS        : Result:='Access forbidden';
  58.   EsockEBADF          : Result:='Alias: bad file descriptor';
  59.   EsockEFAULT         : Result:='An error occurred';
  60.   EsockEINTR          : Result:='Operation interrupted';
  61.   EsockEINVAL         : Result:='Invalid value specified';
  62.   EsockEMFILE         : Result:='Error code ?';
  63.   EsockEMSGSIZE       : Result:='Wrong message size';
  64.   EsockENOBUFS        : Result:='No buffer space available';
  65.   EsockENOTCONN       : Result:='Not connected';
  66.   EsockENOTSOCK       : Result:='File descriptor is not a socket';
  67.   EsockEPROTONOSUPPORT: Result:='Protocol not supported';
  68.   EsockEWOULDBLOCK    : Result:='Operation would block';
  69.  end;
  70. end;
  71.  
  72. {-------------------------------------------------------------------------------
  73. Connect to a server, if not already
  74. -------------------------------------------------------------------------------}
  75. procedure TTCPClient.Connect(IP: String; Port: Integer);
  76. var
  77.  SAddr : TInetSockAddr;
  78. begin
  79.  //Make sure we're not already connected
  80.  if not IsConnected then
  81.  begin
  82.   //Create the socket
  83.   FSocket:=fpSocket(AF_INET,SOCK_STREAM,0);
  84.   //Created OK?
  85.   if FSocket<>-1 then
  86.   begin
  87.    //Set up the server details
  88.    SAddr.sin_family:=AF_INET;
  89.    SAddr.sin_port:=HtoNS(Port);
  90.    SAddr.sin_addr.s_addr:=StrToNetAddr(IP).s_addr;
  91.    //And connect - Timeout is 75 seconds
  92.    if fpConnect(FSocket,@SAddr,SizeOf(SAddr))=-1 then Disconnect; //If not connected.
  93.   end;
  94.  end;
  95. end;
  96.  
  97. {-------------------------------------------------------------------------------
  98. Disconnect
  99. -------------------------------------------------------------------------------}
  100. procedure TTCPClient.Disconnect;
  101. begin
  102.  CloseSocket(FSocket);
  103.  FSocket:=-1;
  104. end;
  105.  
  106. {-------------------------------------------------------------------------------
  107. Receives a response - no timeouts
  108. -------------------------------------------------------------------------------}
  109. function TTCPClient.Receive: String;
  110. var
  111.  Buffer: String[255];
  112.  Lcount: Integer;
  113.  Index : Integer;
  114. begin
  115.  Result:='';
  116.  //Make sure we're connected
  117.  if IsConnected then
  118.  begin
  119.   //Initialise the buffer
  120.   StrPCopy(@Buffer,StringOfChar(#0,255));
  121.   //Then send it
  122.   Lcount:=fpRecv(FSocket,@Buffer,SizeOf(Buffer),0);
  123.   //Copy the response back to the result
  124.   if Lcount>0 then
  125.    for Index:=0 to Lcount do Result:=Result+Buffer[Index];
  126.  end;
  127. end;
  128.  
  129. {-------------------------------------------------------------------------------
  130. Creates the class
  131. -------------------------------------------------------------------------------}
  132. procedure TTCPClient.Send(Output: String);
  133. var
  134.  Buffer: String[255];
  135. begin
  136.  //Make sure we're connected
  137.  if IsConnected then
  138.  begin
  139.   //Copy the query into the buffer
  140.   StrPCopy(@Buffer,Output);
  141.   //Then send it
  142.   fpSend(FSocket,@Buffer,Length(Output),0);
  143.  end;
  144. end;
  145.  
  146. {-------------------------------------------------------------------------------
  147. Destroys the class
  148. -------------------------------------------------------------------------------}
  149. destructor TTCPClient.Destroy;
  150. begin
  151.  if IsConnected then CloseSocket(FSocket);
  152.  inherited Destroy;
  153. end;
  154.  
  155. end.
Use the same unit in a GUI, and I get error 65 (which I can't find any details of what this is, but I assume it'll be "No route to host").
Code: Pascal  [Select][+][-]
  1.  Client      :=TTCPClient.Create;
  2.  Client.Connect('192.168.0.210',23);
  3.  if Client.Connected then

Oh, and I've checked the ESET firewall (even turned it off, again), and gone through the Apple Settings (my application is allowed to access local network). Wireshark doesn't flinch with the GUI application, but does with the console program.

geraldholdsworth

  • Sr. Member
  • ****
  • Posts: 265
Re: Trying, and failing, to create a TCP Client
« Reply #23 on: September 07, 2025, 04:41:34 pm »
OK, this is interesting reading.

As an experiment, I ran the GUI application from Terminal. Lo and behold, it connected (even WireShark noticed).

geraldholdsworth

  • Sr. Member
  • ****
  • Posts: 265
Re: Trying, and failing, to create a TCP Client
« Reply #24 on: September 07, 2025, 11:15:27 pm »
Just to finish off, and in case someone is having the same issue in the future: As an experiment, I compiled the project, then ran the binary (not the package) from where it was compiled and it ran without issue - as it was using Terminal as the launching application. Debugging became an issue though, but I found I could but 'WriteLn' statements throughout the progrm which showed up in Terminal.

Thank you everyone who helped out here with suggestions. It seems that sticking with Synapse would have worked, if we knew that macOS was blocking things (despite the Settings saying otherwise).

 

TinyPortal © 2005-2018