Jump to content
mitzi

wsConnected triggered even if client not connected

Recommended Posts

ICS v8.63

 

hi,

 

I have TSslWSocketThrdServer and TSslWSocket. When server is not active (listening) and client tries to connect, following sequence of state changes is triggered:

State changed: wsClosed->wsOpened
State changed: wsOpened->wsConnecting
State changed: wsConnecting->wsConnected
State changed: wsConnected->wsClosed

 

Why wsConnected is triggered? It is not true, client cannot be connected even for a while when server is down.

It causes big problems when I want to get client reconnected in case of connection lost (or initially not available). I try to connect (in thread) and I get state wsConnected, thread is terminated because connection seems to be established but it is not.

Can you fix it? In my opinion it should trigger wsConnecting->wsClosed as a last state change.

Thanks.

Share this post


Link to post

Why does any of this matter, this is a listening server and there is no thread until after a client connects successfully, which you see from the OnClientConnect event.  The server state should always be wsListening. 

 

BTW, TSslWSocketThrdServer has now been updated or tested for many years, although it descends from TWSocketServer which is heavily used and updated. 

 

Angus

 

Share this post


Link to post

I'm talking about client states, not server.

 

Sequence is taken from TSslWSocket.OnChangeState event.

Share this post


Link to post

Again why does it matter?  The client has already connected to the server by the time the client socket is created and the OnClientConnect event has been triggered.  SocketState is only used by the component to check if the socket needs to closed, there is no connecting state concept for a server listening socket. 

 

Angus

Share this post


Link to post

Well. Maybe we dont understand each other. How can I recognize that tcp client is connected to server? On client side? There’s no property except State. 

Share this post


Link to post

The OnClientConnect event I've mentioned twice is how you know the client is connected.  TSslWSocketClient is not created until after connection is successful, although SSL negotiation may still fail so the socket gets disconnected again. 

 

Servers only ever listen and respond to commands from remote clients, most clients will cleanly disconnect once completed, but you generally don't know if the client is still there which is why most servers have a timeout for an idle client. 

 

Angus

 

Share this post


Link to post
Quote

How can I recognize that tcp client is connected to server? On client side?

On client side, you have the event OnSessionConnected triggered with an error argument being zero. If client can't connect to server, you still have the same OnSessionConnected event triggered but with an error argument not zero, for example 10061 which means the server is not running at the IP/Port/protocol specified.

 

Use state property only for display or log. Use events for everything that "happens" such as connection established or closed or data available and more.

 

Read the comment "About multithreading and event-driven" in OverbyteIcsWSocket.pas (The main source of the sockect component).

Share this post


Link to post

Should have said earlier the main event that tells you a client is connected is receiving data in the onDataAvailable in TSslWSocketClient, this is where any data from the remote client arrives.   You assign this even in the OnClientConnect event.  Very unusual for a server to initiate sending data to a client without receiving something first, even a blank line.

 

Angus

Share this post


Link to post
Posted (edited)

Is it possible to use TSslWSocketThrdClient descendant instead of TSslWSocket on client side? I tried and it worked except one thing. OnSessionClosed is triggered only once and then never again. 

Edited by mitzi

Share this post


Link to post

If you are using TSslWSocketThrdServer then you should be using TSslWSocketThrdClient.  However TSslWSocketThrdServer is itself a descendent of TSslWSocketServer which does not use threads, so it all depends on how you are using the component.  OnSessionClosed is only gone to triggered once since the client is destroyed immediately afterwards. 

 

Presumably you started with the OverbyteIcsThrdSrvV3.dpr sample which is the documentation and sample for TSslWSocketThrdServer, but does not support SSL. 

 

Angus

Share this post


Link to post

Another question: Is there some timeout for connection attempt? When TWSocket tries to connect to server and server does not exist (non-existing ip address or non-listening server) it takes 20 secs than OnSessionClosed is triggered. Can this timeout be changed/set?

 

Thanks for your support

Share this post


Link to post

I assume you are now talking about clients and not servers? 

 

Simple answer is no, TCP is a lazy protocol based on waiting for responses from slow networks (decades ago) so nothing happens fast.  Long answer is Windows allows you to change the TCP timeouts, but such changes effect all applications on the PC and generally it's a very bad idea. 

 

Real solution is to try and ping the server before connecting using TCP, because you can timeout after a few seconds and give up.   ICS has a threaded ping component for this purpose. and a high level client/server component TIcsIpStrmLog that uses ping for exactly this purpose.  TIcsIpStrmLog may be configured as a client or server and allows simple text lines to sent, using few lines of code in the application and only a couple of events.  There is a sample OverbyteIcsIpStmLogTst.dpr that send packets to itself.  The component supports SSL and will order it's own certificates. 

 

Only problem with ping is sometimes it's blocked by firewalls so no response.  You can use a UDP server in parallel with the TCP server for a quick hello, no response is similar to ping. 

 

Angus

 

 

Share this post


Link to post

It is also possible to use a TTimer for desired timeout and call Albort against the socket waiting for connection.

 

Share this post


Link to post

Ehm... guys why so complicated, TWSocket inherits from TCustomTimeoutWSocket if BUILTIN_TIMEOUT define is set so it has both connect timeout and idle timeout.

Share this post


Link to post

TCustomTimeoutWSocket timeouts relate to a socket that is already opened and connected, primarily a server socket, not to TCP DNS and connection attempts.  As Francois says, you can use a timer to abort the connection, but this does not stop the windows connection attempt so the socket can not be re-used immediately for another attempt. 

 

Angus

 

Share this post


Link to post

If ICS uses WinSock.Select for connection then timeout can be set via latest parameter.

Look at following code sample. I modified method from Delphi System.Win.ScktComp.pas and it does exactly what I want. Sets timeout for connection attempt to 5 secs. Originally it took 20 secs too. But I can't use these components :(.

 

procedure TCustomWinSocket.DoOpen;
var
  v: integer;
  WrSet   : TFDSet;
  TimeVal : TTimeVal;
begin
  DoSetASyncStyles;
  Event(Self, seConnecting);

  v:=1;
  IOCtlSocket(FSocket,FIONBIO,v);
  try
    CheckSocketResult(Winapi.WinSock.connect(FSocket, FAddr, SizeOf(FAddr)),'connect');
    TimeVal.tv_sec:=5;
    TimeVal.tv_usec:=0;
    FD_ZERO(WrSet);
    FD_SET(FSocket,WrSet);
    if Select(0,nil,@WrSet,nil,@TimeVal)<>1 then
      CheckSocketResult(1,'select');
  finally
    v:=0;
    IOCtlSocket(FSocket,FIONBIO,v);
  end;

  FLookupState := lsIdle;
  if not (asConnect in FAsyncStyles) then
  begin
    FConnected := FSocket <> INVALID_SOCKET;
    Event(Self, seConnect);
  end;
end;

Couldn't be something like this implemented to ICS?

Share this post


Link to post

No I don't have this intent. I found ICS very usable, but this is, in my opinion, key property ICS should have.

I just wanted to point that this timeout is possible to be set. You wrote it is not possible by design. It seems it is not true.

So my question is whether it is possible to implement this timeout setting to ICS?

 

Consider this situation. I have primary TCP server and backup TCP server. Clients are connected to primary one. If this primary server goes down for any reason, then client loses connection and tries to reconnect. But it can take 20 secs now than it finds server is really inaccessible and then connects to backup server. This reconnection should be as short as possible. Mostly if client is not able to connect within 5 secs server can be considered as inaccessible and then connection to another backup server is processed. But 20 secs is really too long.

 

Your recommendations how to solve this problem when connection timeout cannot be set?

Share this post


Link to post

I have already given my suggestions on how to solve very common issue.   If you need new features you have the ICS source and you can update it yourself.   Or listen to those of us that have been using it for 20 years.

 

Angus

Share this post


Link to post

Your suggestions are no usable. ICMP is security issue and it is no allowed in our environment. Also it only checks IP address accessibility. Not TCP server itself. Other suggestions does not allow the socket to be immediately reused for new connection attempt. 

Do you really think my request is so stupid?

Edited by mitzi

Share this post


Link to post

Why reusing sockets is so important? Do you really have 100000 of active socket handles on the client side?

Share this post


Link to post

If client connect attempt to primary server fails, it needs immediately to connect to another one. If socket is in use even after timer 'breaks' connection attempt by Abort, then next immediate attempt will fail too due to socket is in use, won't it?

Share this post


Link to post

I've explained the limitations of the TCP implementation on Windows and how to get around it.  If you don't want to listen to my experience, feel free to Google for better solutions then let us know when you have a proven working solution.   Many of us have done all this before, often several times. 

 

Angus

 

Share this post


Link to post

Well but this is what I ask for. How did you (or others) solve this scenario? Your suggestion is ping. Well, when ping is successful it tells me nothing about my TCP server, if it is running and listening or not. Other suggestion is to abort connection attempt with timer. But it creates new problem with socket reusing. So what?

It seems there's no useful advice. I will try to make my own port scan via WinSock.Select with timeout set to 5 secs (as I did in my post above for Delphi Socket component) before TWSocket.Connect. Disadvantage is when server is on, then i will do two connection attempts. First by port scan and second with real client connect.  Another one is that this is blocking attempt. 😞

Anyone has better solution?

Edited by mitzi

Share this post


Link to post
3 hours ago, mitzi said:

If client connect attempt to primary server fails, it needs immediately to connect to another one. If socket is in use even after timer 'breaks' connection attempt by Abort, then next immediate attempt will fail too due to socket is in use, won't it?

Well, probably I'm getting it wrong but I see no problem here

SockObj creates socket handle = $111

SockObj tries to connect

SockObj gets timeout

SockObj closes socket handle = $111 and has its internal field FSockHandle set to -1

SockObj creates socket handle = $222

SockObj tries to connect

...

some time later socket handle = $111 really closes and becomes available to the next use

Edited by Fr0sT.Brutal

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×