3

我正在使用 async-await 方法设计一个异步 TCP 服务器,该方法利用具有以下功能的事件驱动的 .NET 环境:

  1. 请求和响应功能。
  2. 服务器端发起的事件。

这种服务器设计在异步等待方法方面是否正确?
下面的代码仅涵盖判断我是否缺少某些东西的基本功能。
服务器使用 COM 类型库,这是 PRMasterAutomation 类的来源。

public class AsyncServer {
    private const int BufferSize = 4096;
    private static bool ServerRunning = true;       
    private List<TcpClient> clients = new List<TcpClient>();
    private PRMasterAutomation automation;

    public AsyncServer()
    {            
        InitializeComponent();
        automation = new PRMasterAutomation();
        automation.OnMonitoringEvent += automation_OnMonitoringEvent;

        if (!automation.Login("ADMIN", "")) 
            return;            

        if (automation.GetPRMasterState() == PRMasterStateEnum.StateIdle)
            automation.StartMonitoring();

        var tcpServer = new TcpListener(IPAddress.Any, 9001);
        tcpServer.Start();
        ListenForClients(tcpServer);                       
    }

    private async void ListenForClients(TcpListener tcpServer)
    {
        while (ServerRunning)
        {
            TcpClient tcpClient = await tcpServer.AcceptTcpClientAsync();
            clients.Add(tcpClient);
            ProcessClient(tcpClient);
        }
    }

    private async void ProcessClient(TcpClient tcpClient)
    {
        var stream = tcpClient.GetStream();
        var buffer = new byte[BufferSize];
        int amountRead;
        string xml;
        while (ServerRunning)            
        {
            if ((amountRead = await stream.ReadAsync(buffer, 0, BufferSize)) > 0)
            {
                var message = Encoding.ASCII.GetString(buffer, 0, amountRead);
                xml = "";
                if (message.Equals("get_users"))
                {
                    xml = automation.GetUsersXml();                                               
                }
                else if (message.Equals("get_events"))
                {
                    xml = automation.GetEventsHistoryXml("");
                }

                if (xml.Length > 0)
                {
                    xml += "\r\n"; 
                    await stream.WriteAsync(Encoding.ASCII.GetBytes(xml), 0, xml.Length);
                }
            }
        }
    }

    async void automation_OnMonitoringEvent(DateTime date, DateTime time, int networkID, int readerID, int userID, int groupID, int eventCode, int zoneID, int TandAID, string strEvent, string strAccessPoint, string strUserSource, string strGroup, string strNetwork, string strZone, string strTandAMode)
    {
        foreach (var c in clients)
        {
            if (c != null && c.Connected)
            {
                var stream = c.GetStream();
                StringBuilder sb = new StringBuilder();
                sb.Append(date.ToString() + ";" + time.ToString() + ";" + networkID.ToString() + ";" + userID.ToString() + "\r\n");
                await stream.WriteAsync(Encoding.ASCII.GetBytes(sb.ToString()), 0, sb.Length);
            }   
        }            
    }
}
4

1 回答 1

4

这种服务器设计在异步等待方法方面是否正确?

是的,但不是在套接字方面。ReadAsync将返回 1 到无穷大之间的任意字节数,它不会返回消息。

Stream.ReadAsync():如果当前可用的字节数小于请求的数量,则结果值可以小于请求的字节数,或者如果已到达流的末尾,则结果值可以为 0(零)。

您必须创建一个缓冲区并继续读取并添加到该缓冲区,直到您知道您收到了整条消息。这意味着检查\r\n您的情况。如果遇到这样的分隔符,可以从缓冲区中提取消息并开始接收新消息。

于 2012-11-22T11:53:33.740 回答