Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The code below has not been tested or should only be considered as guidence. It uses the thread pool for everything. I've put everything in the same file for the example only. You should break up everything into several files.</p> <p>It's important not to let all clients save to the DB directly since that would starve the thread pool. Experiment with the "MaxThreads" constant to get a value that works with your db/server.</p> <p>Also remember that I do not handle any exceptions at all below. You need for instance handle SocketException on BeginRead, EndRead and TcpListener methods.</p> <p>I've tried to use a minimum number of thread sync locks, the code should be quite efficient. The bottle neck will most likely be the database.</p> <pre><code>using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Threading; namespace FastListener { /// &lt;summary&gt; /// Example position class, replace with a real definition /// &lt;/summary&gt; public class Position { public int X { get; set; } public int Y { get; set; } } /// &lt;summary&gt; /// Needed to be able to pass socket/buffer info /// between asynchronous requests. /// &lt;/summary&gt; public struct ClientContext { public Socket socket; public byte[] buffer; } class Program { /// &lt;summary&gt; /// Positions received from mobile clients but not yet saved /// into the database. /// &lt;/summary&gt; private readonly Queue&lt;Position&gt; _positions = new Queue&lt;Position&gt;(); /// &lt;summary&gt; /// Number of threads currently saving stuff to the database. /// &lt;/summary&gt; private int _poolThreads; /// &lt;summary&gt; /// Maximum number of threads that can save info to the database. /// &lt;/summary&gt; private const int MaxThreads = 10; static void Main(string[] args) { new Program().Start(); } private void Start() { TcpListener listener = new TcpListener(IPAddress.Any, 1343); listener.Start(50); listener.BeginAcceptSocket(OnAccept, listener); } // Listener got a new connection private void OnAccept(IAsyncResult ar) { TcpListener listener = (TcpListener) ar.AsyncState; // It's very important to start listening ASAP // since you'll have a lot of incoming connections. listener.BeginAcceptSocket(OnAccept, listener); // I recommend that you create a buffer pool to improve performance byte[] buffer = new byte[400]; // Now accept the socket. Socket socket = listener.EndAcceptSocket(ar); StartRead(new ClientContext {buffer = buffer, socket = socket}); } private void StartRead(ClientContext context) { // start reading from the client. context.socket.BeginReceive(context.buffer, 0, 400, SocketFlags.None, OnReceive, context); } // Stuff from a client. private void OnReceive(IAsyncResult ar) { ClientContext context = (ClientContext) ar.AsyncState; int bytesRead = context.socket.EndReceive(ar); if (bytesRead == 0) { // Put the buffer back in the pool context.socket.Close(); return; } // convert bytes to position. // i'll just fake that here. Position pos = new Position(); // Either handle the request directly if (_poolThreads &lt; MaxThreads) ThreadPool.QueueUserWorkItem(SaveToDatabase, pos); else { // Or enqueue it to let a already active // thread handle it when done with the previous position lock (_positions) _positions.Enqueue(pos); } // Don't forget to read from the client again StartRead(context); } // will save stuff to the database. private void SaveToDatabase(object state) { // Could use Interlocked.Increment, but not really vital if // one more more extra threads are saving to the db. ++_poolThreads; Position position = (Position) state; while (true) { // IMPLEMENT DB SAVE LOGIC HERE. // check if another position is in the queue. lock (_positions) { if (_positions.Count &gt; 0) position = _positions.Dequeue(); else break; // jump out of the loop } } --_poolThreads; } } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload