简体   繁体   中英

C# UDP multiple clients

I have a UDP server in a .NETMF application (the solution would probably be similar for classic .NET Framework 4.5, except that there aren't some classes and methods such as UdpClient). I "start listening" on a socket like this:

_server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
_server.Bind(ep);

And now I want to accept data from a several threads (one thread for every IPEndPoint). The point is to maximize speed. (Note that I am using .NETMF so UdpClient class is not availible).

I had two ideas. First was to create a thread for each expected IPEndPoint and accept/process data there. However the problem is that after a thread accepts data and determines that the accepted source IP/port is different than the assigned IP/port to this thread, this data is thrown away and is not availible for the other appropriate thread anymore. Is there a simple way to fix that? See sample code here:

using System;
using Microsoft.SPOT;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace MFConsoleApplication1
{
    internal class ServerThread
    {
        internal IPEndPoint EP { get; private set; }
        internal Socket Server { get; private set; }
        public ServerThread(IPEndPoint ep, Socket s)
        {
            EP = ep;
            Server = s;
            new Thread(() =>
            {
                byte[] buffer = new byte[2048];
                int byteCount;
                EndPoint recvEP = new IPEndPoint(IPAddress.Any, 0);
                while (true)
                {
                    byteCount = Server.ReceiveFrom(buffer, ref recvEP);
                    if (!recvEP.Equals(EP)) cotinue; //this makes the thread to ignore
                    // to ignore the data as EP is different,but it throw the data away

                    // Process data
                    Debug.Print(byteCount.ToString()); // For example
                }
            }).Start();
        }
    }
}

The other idea is to have one thread which accepts data. When a data chunk is accepted, based on the source IP/port, this thread will create a new Thread to process data. This way doesn't seem to be too elegant as it would require creating tens or hundreds of threads per second. A little imporvement would perhaps be to create threads for each expected IPEndPoint, and to keep them in suspended state till a data for the particular End Point is available.

What is the solution of this problem please?

Thanks for any efforts.

Update The natural approach would be:

_server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
_server.Bind(ep);
while (true)
{
    byteCount = Server.ReceiveFrom(buffer, ref recvEP);
    // Process data
    Debug.Print(byteCount.ToString()); // For example
}

However I need to process data on the basis of the address of the sender. So I could perhaps add a line with similar meaning like:

new Thread(new ParameterizedThreadStart(ProcessData)).Start(recvEP);

and execute it each time after some data is received, but as the server receives tens - hundreds of messages per second this woudn't be too elegant either.

Please suggest an optimum solution for my problem.

First off, when doing embedded stuff like this: Do not spawn threads just to handle work. Use a queue data structure and store just enough information so that you can respond to the request (ie parcel the information). Use 2 system threads, one that does IO and one that processes responses. Let the first one determine if to put a message on the queue. If you don't and you just spawn a thread each time a request comes in you will be susceptible to packet flooding and other DoS exploits; that will eat your limited memory. If there are more than a reasonable number of packages in the queue then stop accepting packages.

Let the second thread be awoken when there are packages to process on the queue. Let it prepare responses to be sent on another queue (like outgoing mail). When there are no more items on the queue it puts itself to sleep.

If the work is compute intensive then use a Run time Loadable procedure to accelerate the work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM