管理TcpClient连接
本文关键字:连接 TcpClient 管理 | 更新日期: 2023-09-27 18:28:50
我有一个设备(步进电机)通过TCP
连接到我的电脑。对发送到设备的消息的响应可以在数秒(通常为3到15秒)后返回
为了与设备通信,经过大量阅读,我想出了以下class
:
public class TcpUtil : IDisposable
{
public event Action<TcpResponse> OnTcpMessage;
private int _port;
private string _ip;
private TcpClient _client;
private NetworkStream _stream;
public TcpUtil(string ip, int port)
{
_ip = ip;
_port = port;
_client = new TcpClient();
//connect with timeout
var connectResult = _client.BeginConnect(ip, port, null, null);
var success = connectResult.AsyncWaitHandle.WaitOne(3000);
if (!success)
{
throw new Exception("Connection timeout at " + ip);
}
// _stream is used for the duration of the object and cannot be used in a using block
_stream = _client.GetStream();
//start listening to incoming messages
Task.Factory.StartNew(() => Listen(_client));
}
private void Listen(TcpClient clientToUse)
{
while (clientToUse.Connected)
{
try
{
byte[] bytes = new byte[1024];
int bytesRead = _stream.Read(bytes, 0, bytes.Length);
string response = Encoding.ASCII.GetString(bytes, 0, bytesRead)
.Replace(Environment.NewLine, "");
if (OnTcpMessage != null && !string.IsNullOrWhiteSpace(response))
{
var message = new TcpResponse(response, _ip);
OnTcpMessage(message);
}
}
catch (Exception ex)
{
if (_client.Connected)
{
Debug.WriteLine("Listener error: " + ex.Message);
throw;
}
}
}
}
public void SendCommand(string command)
{
//device requirement - add a newline at the end of a message
if (!command.EndsWith(Environment.NewLine))
command = command + Environment.NewLine;
byte[] msg = Encoding.ASCII.GetBytes(command);
_stream.Write(msg, 0, msg.Length);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_client != null)
{
_stream.Dispose();
_client.Close();
}
}
}
public void Dispose()
{
Dispose(true);
}
}
我对上面的代码有2个问题:
- 有时结果被连接起来,而不是一个接一个地读取(这确实不一致)
- 我找不到一种可靠的方法来将发送的消息与其响应关联起来
我如何改进上面的代码以使其解决这些问题?
向类中添加一个StreamReader
对象和一个消息队列:
private StreamReader _reader;
private ConcurrentQueue<string> _sentCommands;
初始化变量如下:
_stream = _client.GetStream();
_reader = new StreamReader(_stream, Encoding.ASCII);
_sentCommands = new ConcurrentQueue<string>();
在您的SendMessage
消息中,跟踪您发送的每条消息:
_sentCommands.Enqueue(command);
var msg = Encoding.ASCII.GetBytes(command);
_stream.Write(msg, 0, msg.Length);
然后,当收到消息时,退出队列,您将有一个命令/响应对:
try
{
var response = _reader.ReadLine();
string command;
var result = _sentCommands.TryDequeue(out command);
if (OnTcpMessage != null && !string.IsNullOrWhiteSpace(response))
{
// Do something here to take advantage of the command variable
}
}
//... Rest of code here