Non-Blocking Tcp Server

This is not a question, I'm just looking for some recommendations :) Currently I am writing some kind of abstract tcp server that should use as few streams as possible.

He currently works this way. I have a listener thread and some workflows. The listener thread just sits and waits until the clients connect. I expect that there will be one listener thread per server instance. Worker threads perform all read / write / processing operations on client sockets.

So my problem is creating an efficient workflow. And I came to some problem that I can’t solve yet. The working code is something like this (the code is really simple to show the place where I have my problem):

List<Socket> readSockets = new List<Socket>(); List<Socket> writeSockets = new List<Socket>(); List<Socket> errorSockets = new List<Socket>(); while( true ){ Socket.Select( readSockets, writeSockets, errorSockets, 10 ); foreach( readSocket in readSockets ){ // do reading here } foreach( writeSocket in writeSockets ){ // do writing here } // POINT2 and here the problem i will describe below } 

it works, everyone smoothly agrees to 100% CPU usage due to the fact that the cycle repeats again if I have my clients executing the send-> receive-> disconnect procedure, it doesn’t hurt so much, but if I try to continue to send -> receive-> send-> receive all over again, it really eats the whole processor. So my first idea was to sleep there, I check that all sockets have their own data, and then put Thread.Sleep in POINT2 in just 10 ms, but after 10 ms this will lead to a huge delay of 10 ms when I I want to get the next command from the client socket. For example, if I do not try to “keep alive”, the commands are executed within 10-15 ms and with the preservation of life, it becomes worse by at least 10 ms: (

Maybe it's just bad architecture? What can be done to prevent my processor from getting 100% use and my server to respond to something in the client juice as soon as possible? Maybe someone can point out a good example of a non-blocking server and architecture that it should support?

+4
source share
4 answers

Take a look at the TcpListener class. It has a BeginAccept method that will not block and will call one of your functions when someone connects.

Also consider the Socket class and its Begin methods. They work the same way. One of your functions (a callback function ) is called whenever a certain event is triggered, then you can handle this event. All Begin methods are asynchronous, so they will not be blocked, and they should not use 100% CPU. Basically, you want a BeginReceive for reading and a BeginSend for writing I believe.

You can find more on google by searching for these methods and tutorials for asynchronous sockets. Here's how to implement a TCP client this way, for example. It works almost the same as for your server.

Thus, you do not need an infinite loop, it all depends on the events.

+3
source

Are you building a peer-to-peer application or client server application? You should consider how much data you enter through sockets.

Asynchronous BeginSend and BeginReceive is the way you will need to implement the events, but quickly, as soon as you fix it.

You probably don’t want to set the send and receive timeouts too quickly, but there must be a timeout, so if nothing is received after a certain time, it will exit the block and you can deal with it there,

+1
source

Microsoft has a good example of an asynchronous TCP server. It takes a little to wrap your head around you. It was a few hours of my time before I could create a basic TCP structure for my own program based on this example.

http://msdn.microsoft.com/en-us/library/fx6588te.aspx

The logic of the program looks something like this. There is one thread that calls listener.BeginAccept and then blocks allDone.WaitOne. BeginAccept is an asynchronous call that is uploaded to threadpool and handled by the OS. When a new connection arrives, the OS calls the callback method passed with BeginAccept. This method exposes allDone so that the main listening thread knows that it can listen again. The callback method is just a transient method and continues to call another asynchronous call to receive data.

The callback method provided by ReadCallback is the main “loop” of work (actually recursive asynchronous calls) for asynchronous calls. I use the term "loop" loosely because each method actually calls termination, but not until the next asynchronization method is called. In fact, you have a bunch of asynchronous calls that all call each other, and you pass in your "state" object. This object is your own object, and you can do whatever you want with it.

Each callback method gets only two things returned when the OS calls your method:

1) A socket object representing a connection

2) The state object that you use for your logic

With the state object and the socket object, you can efficiently process your “connections” asynchronously. The OS is very good at that.

In addition, since your main loop blocks waiting for a connection and unloads these connections into the thread pool through asynchronous calls, it no longer works in most cases. The thread pool for your sockets is handled by the OS through the completion ports, so they do not do any real work until the data appears. A very small processor is used, and it is effectively threaded through the thread pool.

PS From what I understand, you don’t want to do the hard work with these methods just by handling data movement. Since the thread pool is the pool for your network I / O and is used by other programs, you must offload any hard work through threads / tasks / asynchronous process so as not to cause the socket thread pool to fail.

PPS I did not find a way to close the listening connection, except to simply dispose of the "listener". Since the asynchronous call to beginListen is called, this method will never return until the connection is made, which means that I cannot tell it to stop until it returns. I think I'll post a question about MSDN on it. and a link if I get a good answer.

0
source

Everything is in order, this is your code except for the timeout. You set it to 10 microseconds (10 * 10 ^ -6), so your procedure is repeated very often. You must set an adequate value (for example, 10 seconds), and your code will not consume 100% CPU.

 List<Socket> readSockets = new List<Socket>(); List<Socket> writeSockets = new List<Socket>(); List<Socket> errorSockets = new List<Socket>(); while( true ){ Socket.Select( readSockets, writeSockets, errorSockets, 10*1000*1000 ); foreach( readSocket in readSockets ){ // do reading here } foreach( writeSocket in writeSockets ){ // do writing here } // POINT2 and here the problem i will describe below } 
0
source

Source: https://habr.com/ru/post/1307893/


All Articles