Jump to content
mitzi

TCP Client in thread

Recommended Posts

Hello,

 

I need to implement TCP client(s) in thread(s) with reconnect feature (if connection is closed with error then client tries to reconnect) which should run in service. I created server and client demo app to test this concept but I met following issues and I'm really not able to find out what's wrong in my implementation.

  1.  When I run server, start it and start internal client (client implemented the same exe) server throws "error:00000000:lib(0):func(0):reason(0), State: before SSL initialization, connection closed unexpectedly" in OnSslHandshakeDone and disconnects client. When I start (the same) client as standalone exe, it works.
  2. When I run and start server, then run and start standalone client and then kill server app (to simulate connection error) client starts to reconnect and when server is started again TWO client connections are established (!?) from client application. The second one is correct and the first one is some ghost or whatever.
  3. Sometimes while client tries to reconnect after text is received from server or sent to server, first connection attempt causes various exceptions and client thread is terminated.

 

Can you please inspect my code in attachment? Test self-signed certificate for SSL is included (SSC.pfx).

 

Thanks in advance

 

ICSTCP.ZIP

Edited by mitzi

Share this post


Link to post

First of all, would you please explain why you need TCP in threads? TWSocket and all derived classes are non-blocking and don't need to be use in thread.

Edit your question to add the reason for a thread.

 

Edited by FPiette

Share this post


Link to post

Planned service should read data from many TCP clients (connected to various TCP servers), process them and send results to other TCP servers. When I tested this concept in non-thread env I found out that clients first read data from their connections (in main thread) and after all data is read then processed results are sent to servers. It is not parallel. Data reading in main thread blocked sending. There's buffer that receives results from data processing threads and out clients should pop up data from it immediately when they are available and send them out. But this is blocked because main thread is busy due to OnDataAvailable events from reading clients. I need TCP clients to read and send data in threads. Maybe I simply don't use ICS correctly, so please point me correct way.

 

Share this post


Link to post
42 minutes ago, mitzi said:

in non-thread env I found out that clients first read data from their connections (in main thread) and after all data is read then processed results are sent to servers. It is not parallel. Data reading in main thread blocked sending.

Then you use the component incorrectly. You probably made a loop instead of using events. I don't know since you don't show your code.

The only thing that could block is your processing if it is to long. Then you should put your processing in a thread if it can not be rewritten as asynchronous.

 

The key is to NOT have loops.

 

Share this post


Link to post

I have a commercial ICS application called ComCap with multiple clients accepting data from SSL servers and forwarding that data to other SSL servers, all without threads, it has retries for lost connections.  It makes heavy use of the TIcsIpStrmLog component which runs as a client or server, and has been tested with over 1,000 simultaneous sessions, no threads, no exceptions.

 

Suggest you look at the OverbyteIcsIpStmLogTst sample and see if you can simplify your application by using TIcsIpStrmLog to replace your TWSocket and TWSocketServers compoents.

 

Angus

 

Share this post


Link to post
Guest

@FPiette I want to suggest a new demo for ICS, 

 

A proxy, plain simple one, can be used/extended to build 

1) just proxy 

2) monitoring and debugging

3) extended to be load balancer

4) first defense wall against flooding or DDoS attacks, allowing one to hide his more critical server on different machine, (filtering)

 

I looked at ICS demos and don't see one, while in my opinion such demo is useful and more than that it should be written right, as it an easy task, i think ICS library in need for one written by you or Angus.

Share this post


Link to post

No problem, I can rewrite demos to use standard non-thread model (they were written such way in the beginning).

Share this post


Link to post
Quote

A proxy, plain simple one, can be used/extended to build  

I looked at ICS demos and don't see one

Not sure what this has to do with this thread.

 

Suggest you look at the OverbyteIcsProxySslServer.dpr sample.  The ICS proxy component can be used as a forward or reverse proxy with logging.

 

Angus

 

 

  • Like 1

Share this post


Link to post

Well, I'm really lost. I need several tcp clients to pop data from buffer simultaneously and send them as quick as possible. I need either timer or loop for this, but both are blocking, or thread where tcp client is its member but it does not work correctly :(. If there were some event like OnIdle or something like that where I would call pop and send when socket is ready or available then I understood how to do it without thread. But I didn't find anything like that. Buffer is fed with data from several processing threads massively so it is not too good idea to trigger all sending clients from it.

Edited by mitzi

Share this post


Link to post
Guest
13 minutes ago, mitzi said:

I need several tcp clients to pop data from buffer simultaneously and send them as quick as possible.

That exactly why i suggest to have the same build as proxy, ( my bad that i don't have all the folders of ICS and missed that a proxy is there)

 

You need the same mechanism that proxy utilize to be used in your client, because proxy by definition should and can handle many request in separated way, the part from proxy you need is the out/forward connection, means you need to look how ICS proxy is build and forward the data, but in your case you will just execute the requests and repeat the failed ones.

Share this post


Link to post
29 minutes ago, mitzi said:

I need several tcp clients to pop data from buffer simultaneously and send them as quick as possible. I need either timer or loop for this, but both are blocking, or thread where tcp client is its member but it does not work correctly

I don't know what your buffer is. Put the idea is to PostMessage a custom message to the thread (probably main thread) handling communication. This message would include a pointer to a dynamically allocated structure (buffer) holding the data to be sent. The message handler will the call Send against the TWSocket in charge of sending data and then free the structure allocated (important). Send method is non blocking. It will copy data to an internal buffer that the TWSocket will send as fast as possible. When the buffer is emptyed, TWSocket sent an OnDataSent event you may use to getting more data from the buffer or just ignore it. If you ignore it, be aware that TWSocket may buffer a large amount of data when the network speed is slower than the speed at which data comes from your buffer. But anyway, either your buffer fills or TWSocket buffer fills.

Share this post


Link to post

I really don't know what is wrong with thread containing TWSocket where in Execute method buffer is repeatedly asked for data and if data is available then TWSocket sends it. Why this solution is not recommended?  Buffer is FIFO and it is (and should be) independent of any communication or messaging. It features Push and Pop methods and it is up to any kind of client to ask it for data or feed it with data. No trigger mechanism is usable because if new client is created it simply can't wait for any message signalling there's data available. It must look itself for it. Repeatedly. Thread is the best solution for this in my opinion. Only problem is with issues I mentioned in initial post.

Share this post


Link to post
19 minutes ago, mitzi said:

I really don't know what is wrong with thread containing TWSocket

There is nothing wrong but it is much much more complex to write correctly and debug in case of problem. Also it is less efficient (Use more CPU).

20 minutes ago, mitzi said:

Why this solution is not recommended?

Because it is almost always not needed since TWSocket is asynchronous (non-blocking). It can sustain hundreds of connections per thread because most of the work is done by the kernel. You need thread for lengthy processing that cannot be programmed as asynchronous task, not for socket communication.

23 minutes ago, mitzi said:

Buffer is FIFO and it is (and should be) independent of any communication or messaging.

That is perfect.

24 minutes ago, mitzi said:

It features Push and Pop methods and it is up to any kind of client to ask it for data or feed it with data.

That is perfect for TWSocket. OnDataSent can be used to pop data from FIFO when previous data has been sent. If there is not data available at that time, use a timer to check later if there is no mechanism in your FIFO to signal data is available. This is a kind of polling which is not to much resource hungry.

27 minutes ago, mitzi said:

No trigger mechanism is usable because if new client is created it simply can't wait for any message signalling there's data available. It must look itself for it. Repeatedly.

This is bad design because - you don't name it - it is a polling. And polling has poor performance. Either the polling period is very short and consume a lot of CPU for nothing or the polling period is to long and this introduce delay. You'd better implement a notification system in your FIFO.

 

I don't clearly understand your architecture. Specifically what are the clients. You talked about "internal" client and client in other exe)? Which data they must receive ? Does all clients receive all data, or each client receive a chunk of data and his the only one receiving that chunk of data?). Are the client requesting data periodically ? Are the client just connecting and wait on their side that data arrives?

 

You'll get the best advice if I (and others) clearly understand what your problem is.

 

Share this post


Link to post

TCP clients are connected to devices (servers) or devices connects to TCP servers as clients and receive raw data to stream. Once the data is identified as valid input (data has header and terminator or etc) it is passed to thread which parses data by protocol (defined by header) and creates unified "signal" structure which is pushed to Buffer. Many data sources feed this Buffer this way (hundreds data packets per second). Other TCP clients are connected to other application (TCP server) which processes these signals.

More sending TCP clients ensure faster signal delivery to main app. See attached scheme.

 

Screenshot_001.png

Share this post


Link to post

So almost the same as my ComCap application, which works fine without threads, except for adding the captured data to a SQL database which is queued then added in a thread.  Read my previous message again.

 

Angus

 

Share this post


Link to post
4 hours ago, mitzi said:

TCP clients are...

Thanks for explanation. It is more clear. Still one unanswered point: Has the data in the FIFO to be sent to all client devices as well as the external client? Or is there a routing mechanism sending data poped out of the FIFO to the right client?

 

4 hours ago, mitzi said:

Other TCP clients are connected to other application (TCP server) which processes these signals.

Although possible, I think it unusual that a window service act as a client for an application. Usually it is the reverse.

 

I would suggest a change in the architecture:

 

660073274_Sanstitre.thumb.png.6ebb2cc000e504e89ac2727995fa60e0.png

 

A single TCP stream is enough between Windows service and client application. It is likely that this is not the bottle neck. The real bottle neck is probably in the processing, either because it is CPU bound or because it update a slow GUI or do some blocking database stuff. That's why I use a single TCP stream feeding a FIFO which is emptied by as many processing threads (maybe one per CPU core if CPU bound or more if I/O bound).

 

 

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
×