管理TcpClient连接

时间:2016-01-04 13:26:38

标签: c# tcp tcpclient

我有一台设备(步进电机)通过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个问题:

  • 有时候结果是连接在一起的,而不是逐个阅读(这确实是不一致的)
  • 我找不到一种可靠的方式将已发送的消息与其“
  • ”相关联

如何改进上述代码以解决这些问题?

1 个答案:

答案 0 :(得分:0)

向您的类添加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