帮助事件驱动的TCP服务器

时间:2011-03-16 12:34:39

标签: c# tcp event-driven

我正在开发一个“应用程序系统”,我还需要创建一个服务器应用程序。我在C#(.NET 4.0)工作。服务器将主要收集来自不同POS应用程序/客户端的数据(应该是大约50-100,但服务器应该能够处理大约200-300个客户端)。从单个客户端,服务器可能每天大约100x次接收大约1KB。服务器主要需要接受数据,解密并将其存储到磁盘。它还应该检查特定目录中的更改,以便向客户端发送新配置,这不应该经常发生。

我对C#和服务器编程很陌生,所以请耐心等待。我考虑过使用线程池和异步方法(在一本书中简单地使用了一个很好的例子“C#”)。但我花了很多时间寻找最佳解决方案,我发现了这一点。但在我的情况下,多线程带来的问题多于好处。因此我想到了甚至驱动服务器。 “一个进程,在回调中处理每个事件(接受的连接,可读取的数据,可以写入客户端,......)。”来自“what is event driven web server”。我发现这是解决我问题的最佳方法。

但我不知道如何编码,我找不到任何关于事件驱动服务器的例子。据我所知,我应该创建一个线程(GUI为+ 1),然后创建一个TCP侦听器然后以某种方式创建事件,以便当TCP侦听器可以接受客户端时,事件将触发并唤醒服务器,同样在数据时从客户端读取将可用它将唤醒服务器。

请帮我编代码,我完全迷失了。我知道如何使用

来做到这一点
while(true)
{
   check if client wants to connect
        accept client and add it to client list
   iterate through client list and check if anyone is sending data ...
        accept data and store it
   ...
  }

但这不是事件驱动的,而是在浪费CPU。服务器不会非常活跃,所以我想让它尽可能高效。

一些例子确实会有所帮助。

感谢您的时间和答案。

P.S。我可以只为所有客户端使用一个端口吗?

编辑:为了澄清,我想编写一个事件驱动的服务器代码,但我不知道如何编写,因此我只是做了一个我所知道的例子(客户端轮询)。

6 个答案:

答案 0 :(得分:3)

首先,如果您是C#和多线程和套接字的新手,那就是批次来为您的第一个项目做好准备。我建议单独学习这些。

也就是说,您可能会发现Nito.Async.Sockets有帮助;它包括一个事件驱动的服务器套接字,并为您处理多线程问题。

答案 1 :(得分:1)

我不了解C#框架,但您可以查看一个事件驱动的Python框架Twisted。您可以找到与您的需求类似的服务器和客户端代码示例。

以下是一个非常简单的服务器示例,它回应客户端从它收到的任何内容:

#!/usr/bin/env python

# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
# See LICENSE for details.

from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor

### Protocol Implementation

# This is just about the simplest possible protocol
class Echo(Protocol):
    def dataReceived(self, data):
        """
        As soon as any data is received, write it back.
        """
        self.transport.write(data)


def main():
    f = Factory()
    f.protocol = Echo
    reactor.listenTCP(8000, f)
    reactor.run()

if __name__ == '__main__':
    main()

关于你的上一个问题:

  

P.S。我可以只为所有客户端使用一个端口吗?

是的,您可以(无论您使用何种语言/框架)。

答案 2 :(得分:1)

我建议使用托管为Windows服务的WCF,它提供可扩展的多线程平台。它也可以根据协议要求进行定制。这是一个可以作为参考的例子:

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

答案 3 :(得分:1)

事件驱动并不能准确描述您希望系统工作的内容,因为您描述了轮询客户端以处理要处理的数据而不是客户将其数据推送到您的服务(触发事件)。

如果您对如何对此类系统进行编码知之甚少,可以查看适用于您的方案的现有解决方案/产品。

我建议您检查一下EAI工具,例如BlueIntegratorBizTalk,以便整合POS客户端。

有关推出客户端更新的要求,您可以查看BITS

答案 4 :(得分:1)

这是您可能需要的服务器框架。没有例外处理。

class Program
{
    public static ManualResetEvent connected = new ManualResetEvent(false);

    static void Main(string[] args)
    {
        string ip = "127.0.0.1";
        int port = 14500;

        TcpListener server = new TcpListener(IPAddress.Parse(ip), port);
        server.Start();

        Console.WriteLine("Server started...");

        while (true)
        {
            connected.Reset();
            server.BeginAcceptTcpClient(new AsyncCallback(AcceptCallback), server);
            connected.WaitOne();
        }
    }

    public static void AcceptCallback(IAsyncResult ar)
    {
        TcpListener listener = (TcpListener)ar.AsyncState;
        TcpClient client = listener.EndAcceptTcpClient(ar);

        byte[] buffer = new byte[1024];
        NetworkStream ns = client.GetStream();
        if (ns.CanRead)
        {
            ns.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(ReadCallback), new object[] { ns, buffer });
        }

        connected.Set();
    }

    public static void ReadCallback(IAsyncResult ar)
    {
        NetworkStream ns = (NetworkStream)((ar.AsyncState as object[])[0]);
        byte[] buffer = (byte[])((ar.AsyncState as object[])[1]);
        int n = ns.EndRead(ar);
        if (n > 0)
        {
            Console.WriteLine(Encoding.ASCII.GetString(buffer, 0, n));
        }
        ns.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(ReadCallback), new object[] { ns, buffer });
    }
}

答案 5 :(得分:0)

我有点迟到了,但我最近开始了一项新工作,开发软件与科学仪器集成,目前正在经历学习线程,通信,异步处理等的痛苦。我发现Joe Albahari的Threading in C#是学习线程方面的优秀资源。