c# - 使数据接收/数据监听器保持事件状态的最佳方法是什么?

标签 c# async-await tcp

我的任务是创建一个通过 TCP 进行数据通信的客户端应用程序,但我没有 TCP 数据通信编程方面的经验。我使用 C# 和 VS2013。在我工作的公司中,有一个黑盒服务器应用程序。我只知道它的ip、端口和它在数据通信上的行为:

  1. 它正在等待 XML 格式和 UTF8 编码的消息。其他格式或编码将被忽略。
  2. 一旦收到消息,它就会将收到的消息作为确认发回。
  3. 服务器也可以在不先从客户端接收消息的情况下向客户端发送另一条消息。

我已经实现了第 1 点和第 2 点(请参阅下面的代码),它们有效。但是我很困惑(在第 3 点)如何将“等待和接收数据”部分变成一个循环,在客户端应用程序关闭之前一直保持事件状态。在此先感谢您的帮助和提示。

using System;
using System.Net.Sockets;
using System.Text;

namespace ConsoleTest01
{
    public class Program
    {
        private const String _xmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
        private const String _xmlEndTag = "</xml>";
        private static TcpClient _client;
        private static NetworkStream _stream;

        static void Main(string[] args)
        {
            Connect("127.0.0.1", 4502, "<DummySettings></DummySettings>");
        }

        static void Connect(String server, Int32 port, String message)
        {
            try
            {
                _client = new TcpClient(server, port);

                // Prepare data
                message = _xmlHeader + message + _xmlEndTag;
                Byte[] data = UTF8Encoding.UTF8.GetBytes(message);
                Byte[] suffix = UTF8Encoding.UTF8.GetBytes("\r\n");
                Byte[] utf8Result = new byte[data.Length + suffix.Length];
                Buffer.BlockCopy(data, 0, utf8Result, 0, data.Length);
                Buffer.BlockCopy(suffix, 0, utf8Result, data.Length,      suffix.Length);

                // Send data
                if (_client != null) _stream = _client.GetStream();
                _stream.Write(utf8Result, 0, utf8Result.Length);
                Console.WriteLine("Sent: {0}", message);

                // Waiting and receive data
                var acknowledgement = new Byte[data.Length + suffix.Length];
                String responseData = String.Empty;
                Int32 bytes = _stream.Read(acknowledgement, 0,     acknowledgement.Length);
                responseData = UTF8Encoding.UTF8.GetString(acknowledgement, 0, bytes);
                Console.WriteLine("Received: {0}", responseData);

                // In real life the close commands are not called here.
                _stream.Close();
                _client.Close();
            }
            catch (ArgumentNullException e)
            {
                 Console.WriteLine("ArgumentNullException: {0}", e);
            }
            catch (SocketException e)
            {
                 Console.WriteLine("SocketException: {0}", e);
            }

            Console.WriteLine("\n Press Enter to continue...");
            Console.Read();
        }
    }
}

编辑:关于我的代码的更多信息。

使用上面的代码,我可以向服务器发送消息获得服务器的确认,然后根据设计关闭应用程序,因为它只是我的实验代码。用户 Prabhu 正确理解了我的情况。

现在我想知道如何实现只接收部分来处理服务器向我的客户端发送另一条消息并且我的客户端可以处理该消息的情况。因此,接收部分应该保持事件状态以监听传入消息,直到我的客户端应用程序关闭。它可能涉及后台线程(我没有经验)。非常感谢示例代码(或指向它的链接)。

最佳答案

您需要围绕发送-接收对包装一个循环:

while (true) {
 var data = ...;
 Send(data);
 var receivedData = Receive();
 Debug.Assert(data == receivedData);
}

就像那样。

因为没有两个操作同时发生,所以没有必要使用异步 IO 或线程。我特别建议不要使用非阻塞套接字和“select”方法,因为它在带有 await 的 .NET 4.5 上已经过时了。

您当前的代码已损坏,因为它假定读取操作将返回特定数量的字节。事实并非如此,请参阅文档。

使用 BinaryReader 轻松读取精确的字节数。

关于c# - 使数据接收/数据监听器保持事件状态的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30392452/

相关文章:

c# - C#中随机生成的十六进制数

Android TCP 在套接字关闭之前不会刷新

Java TCP。如何确认你收到的数据包是一个完整的数据结构?

c# - HttpClient 解码编码的 Url?

应用了不同操作集的 C# 类

c# - IEnumerable.ToArray<T>() 与 IEnumerable.Cast<T>().ToArray()

c# - [ThreadStatic] 的使用与异步代码不一致吗?

c# - 如何在新线程上运行任务并立即返回给调用者?

.net - 面向 4.0 部署要求的 Async Await

java - 从输入流 Java 读取时有没有超时的方法?