C# 使数据接收/数据侦听器保持活动状态的最佳方法是什么?
我的任务是创建一个通过TCP进行数据通信的客户机应用程序,我没有TCP数据通信编程的经验。我使用C#和VS2013。在我工作的公司里有一个黑盒服务器应用程序。我只知道它的ip、端口和它在数据通信上的行为:C# 使数据接收/数据侦听器保持活动状态的最佳方法是什么?,c#,async-await,tcp,C#,Async Await,Tcp,我的任务是创建一个通过TCP进行数据通信的客户机应用程序,我没有TCP数据通信编程的经验。我使用C#和VS2013。在我工作的公司里有一个黑盒服务器应用程序。我只知道它的ip、端口和它在数据通信上的行为: 它正在等待XML格式和UTF8编码的消息。其他格式或编码将被忽略 一旦收到消息,它就会将收到的消息作为确认发送回 服务器还可以向客户端发送另一条消息,而不必首先从客户端接收消息 我已经实现了第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();
}
}
}
使用系统;
使用System.Net.Sockets;
使用系统文本;
名称空间控制台测试01
{
公共课程
{
私有常量字符串_xmlHeader=“”;
私有常量字符串_xmlEndTag=“”;
专用静态TcpClient\u客户端;
私有静态网络流_流;
静态void Main(字符串[]参数)
{
连接(“127.0.0.1”,4502,”;
}
静态void连接(字符串服务器、Int32端口、字符串消息)
{
尝试
{
_客户端=新的TcpClient(服务器、端口);
//准备数据
消息=_xmlHeader+消息+_xmlEndTag;
Byte[]data=UTF8Encoding.UTF8.GetBytes(消息);
字节[]后缀=UTF8Encoding.UTF8.GetBytes(“\r\n”);
字节[]utf8Result=新字节[data.Length+后缀.Length];
块复制(数据,0,utf8Result,0,数据.长度);
块复制(后缀,0,utf8Result,数据.长度,后缀.长度);
//发送数据
如果(_client!=null)_stream=_client.GetStream();
_stream.Write(utf8Result,0,utf8Result.Length);
WriteLine(“发送:{0}”,消息);
//等待并接收数据
var确认=新字节[data.Length+后缀.Length];
String responseData=String.Empty;
Int32字节=_stream.Read(确认,0,确认.长度);
responseData=UTF8Encoding.UTF8.GetString(确认,0,字节);
WriteLine(“接收:{0}”,responseData);
//在现实生活中,这里不调用close命令。
_stream.Close();
_client.Close();
}
捕获(e)
{
WriteLine(“ArgumentNullException:{0}”,e);
}
捕获(SocketException e)
{
WriteLine(“SocketException:{0}”,e);
}
Console.WriteLine(“\n按Enter键继续…”);
Console.Read();
}
}
}
编辑:有关我的代码的更多信息
使用上面的代码,我可以向服务器发送消息并获得服务器的确认,然后根据设计关闭应用程序,因为它只是我的实验代码。用户Prabhu正确理解我的案例
现在,我想知道如果服务器向我的客户机发送另一条消息,而我的客户机可以处理该消息,如何实现仅接收部分来处理该情况。因此,接收部分应该保持活动状态,以侦听传入消息,直到我的客户端应用程序关闭。它可能涉及后台线程(我没有这方面的经验)。非常感谢您提供示例代码(或其链接)。您的应用程序要求使用非阻塞套接字。As事件可以异步发生
选择机制进行监控。称之为套接字线程。将数据发送到服务器的线程-称之为工作线程
连接的插座idsd
应与螺纹共享。当工作线程有数据要发送到服务器时,它应该在连接的sd
上执行send
。服务器的响应应该唤醒sd
上的套接字线程轮询。它应该完全接收消息(应用程序应该负责识别完整的消息),并将数据传递给工作线程进行处理
类似地,当服务器消息(无响应)传入时,套接字线程将被唤醒。应将其传递给工作螺纹
工作线程可以在事件循环中执行上面列出的操作。您需要围绕发送-接收对包装一个循环:
while (true) {
var data = ...;
Send(data);
var receivedData = Receive();
Debug.Assert(data == receivedData);
}
像那样
因为没有两个操作同时发生,所以没有必要使用异步IO或线程。我特别建议不要使用非阻塞套接字和“select”方法,因为它在.NET4.5的wait中已经过时了
当前代码已中断,因为它假定读取操作将返回特定数量的字节。事实并非如此,请参阅文档
使用BinaryReader
轻松读取准确的字节数。最后我找到了问题的解决方案。我不确定这是否是一个最佳实践,但它在我的情况下起作用。如果有人有更好的想法来改进我的解决方案,请让我知道
背景工作者:
private static void StartListening()
{
_dataLength = (_dataLength < (32 * 1024)) ? 32 * 1024 : _dataLength;
while (!_shouldStop) // _shouldStop is a boolean private field
{
try
{
if (_stream.DataAvailable) // _stream is a NetworkStream
{
Byte[] buffer = new Byte[_dataLength];
Int32 readBytes = _stream.Read(buffer, 0, buffer.Length);
// ResponseData is a property of type String
ResponseData = UTF8Encoding.UTF8.GetString(buffer, 0, readBytes);
}
}
catch (IOException ioex)
{
// Do nothing since the client and socket are already closed.
}
}
}
如果您自己不确定,我们很难解释您的要求,但我最好的猜测是,您应该按需为3(而不是3)打开与客户的连接
_shouldStop = false;
var t = new Thread(MyClass.StartListening);
t.IsBackground = true;
t.Start();