我在C#中使用TcpClient类。
每次有新的tcp连接请求时,通常的做法是创建一个新线程来处理它。并且主线程应该可以随时终止这些处理程序线程。
我对这些处理程序线程的解决方案如下:
1 Check NetworkStream's DataAvailable method
1.1 If new data available then read and process new data
1.2 If end of stream then self terminate
2 Check for terminate signal from main thread
2.1 If terminate signal activated then self terminate
3 Goto 1.
这种轮询方法的问题在于所有这些处理程序线程将占用大量处理器资源,尤其是如果存在大量这些线程的话。这使得效率非常低。
有更好的方法吗?
答案 0 :(得分:2)
请参阅Asynchronous Server Socket Example以了解如何以“.NET方式”执行此操作,而无需为每个请求创建新线程。
答案 1 :(得分:1)
信不信由,1000滴睡眠会让事情顺利进行。
private readonly Queue<Socket> sockets = new Queue<Socket>();
private readonly object locker = new object();
private readonly TimeSpan sleepTimeSpan = new TimeSpan(1000);
private volatile Boolean terminate;
private void HandleRequests()
{
Socket socket = null;
while (!terminate)
{
lock (locker)
{
socket = null;
if (sockets.Count > 0)
{
socket = sockets.Dequeue();
}
}
if (socket != null)
{
// process
}
Thread.Sleep(sleepTimeSpan);
}
}
答案 2 :(得分:0)
我记得在开发类似的Windows服务。这是一个NTRIP服务器,可以接收大约1000个TCP连接并将数据路由到NTRIP Caster。
如果你有一个专用的服务器用于这个应用程序,那么除非你为每个线程添加更多的代码(文件IO,数据库等),它不会有问题 - 尽管在我的情况下我也有数据库处理来记录输入/输出每个连接)。
需要注意的事项:
上述内容可能不适用于您的情况,但我只是想把它放在这里,因为我在开发过程中遇到了这个问题。
答案 3 :(得分:0)
你是对的,你不希望所有的线程“忙着等待”(即一遍又一遍地运行一个小循环)。您要么阻止它们,要么想要使用异步I / O.
正如John Saunders所提到的,异步I / O是实现这一目标的“正确方法”,因为它可以扩展到数百个连接。基本上,您调用BeginRead()并向其传递回调函数。 BeginRead()立即返回,当数据到达时,将在线程池的线程上调用回调函数。回调函数处理数据,再次调用BeginRead(),然后返回,将线程释放回池中。
但是,如果您一次只打开几个连接,那么为每个连接创建一个线程就完全没问题了。不要在循环中检查DataAvailable属性,而是继续调用Read()。线程将阻塞,不占用CPU,直到数据可供读取。如果连接丢失,或者您从另一个线程关闭它,则Read()调用将抛出异常,您可以通过终止读取器线程来处理该异常。