我在.NETMF应用程序中有一个UDP服务器(对于经典的.NET Framework 4.5,解决方案可能类似,除了没有一些类和方法,如UdpClient)。我在这样的插座上“开始听”:
_server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
_server.Bind(ep);
现在我想接受来自多个线程的数据(每个IPEndPoint一个线程)。关键是要最大化速度。 (请注意,我使用的是.NETMF,因此无法使用UdpClient类。)
我有两个想法。首先是为每个预期的IPEndPoint
创建一个线程并在那里接受/处理数据。但问题是,在线程接受数据并确定接受的源IP /端口与分配给该线程的IP /端口不同之后,该数据将被丢弃,并且不再适用于其他适当的线程。有没有一种简单的方法来解决这个问题?请在此处查看示例代码:
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();
}
}
}
另一个想法是让一个线程接受数据。当接受数据块时,基于源IP /端口,该线程将创建一个新线程来处理数据。这种方式似乎并不太优雅,因为它需要每秒创建数十或数百个线程。稍微改进的可能是为每个预期的IPEndPoint创建线程,并保持它们处于挂起状态,直到特定端点的数据可用为止。
请问这个问题的解决方案是什么?
感谢您的任何努力。
更新 自然的方法是:
_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
}
但是我需要根据发件人的地址处理数据。所以我也许可以添加一个具有类似含义的行:
new Thread(new ParameterizedThreadStart(ProcessData)).Start(recvEP);
并在每次收到一些数据后执行它,但由于服务器每秒收到数十封邮件,这也不会太优雅。
请为我的问题建议一个最佳解决方案。
答案 0 :(得分:1)
首先,当做这样的嵌入式东西时:不要只是为了处理工作而产生线程。使用队列数据结构并存储足够的信息,以便您可以响应请求(即包裹信息)。使用2个系统线程,一个执行IO,另一个执行处理响应。让第一个确定是否在队列中放置消息。如果你不这样做而且每次请求进入时你只是产生一个线程,你将容易受到数据包泛滥和其他DoS攻击的影响;这将占用你有限的记忆。如果队列中的包数超过合理数量,则停止接受包。
当队列中有要处理的包时,让第二个线程被唤醒。让它准备响应发送到另一个队列(如外发邮件)。当队列中没有其他项目时,它会让自己进入睡眠状态。
如果工作是计算密集型的,那么使用“运行时可加载”过程来加速工作。