【问题标题】:Sending Multiple Commands in TCPClient在 TCPClient 中发送多个命令
【发布时间】:2012-06-08 05:08:31
【问题描述】:

我正在尝试使用

private TcpClient tcpClient;

在课堂上,每次我发送LISTRETRSTOR 之类的命令时,我都会在执行命令和获得响应的特定时间锁定 TCPClient。

现在,当我在执行之间发送另一个命令时,它无法再次锁定该 tcpclient 实例。

当一个命令正在执行时我应该如何发送另一个命令。对于我需要锁定 TCPClient 的所有命令,我无法更改。

【问题讨论】:

    标签: c# .net tcpclient


    【解决方案1】:

    这是一个设计问题。您需要设计一种访问 TcpClient 的多线程方式,而不会过度锁定它

    我可以建议您使用队列而不是锁定 TcpClient 吗?我认为您正在尝试构建 FTP 客户端。 (我根据 LIST、RETR 和 STOR 命令猜测)。

    一个简单队列的例子

    private TcpClient client;
    private Queue<string> commands = new Queue<string>();
    private AutoResetEvent resume = new AutoResetEvent(false);
    
    public void Add(string cmd)
    {
      lock(commands) { commands.Enqueue(cmd); }
      resume.Set();
    
    }
    
    private void ThreadRun() // this method runs on a different thread
    {
       while(!quit.WaitOne(0,true))
       {
          resume.WaitOne();
          string command;
          lock(commands) { command = commands.Dequeue(); }
          Process(command);
    
       }
    
    
    }
    

    您应该避免仅仅为了使其线程安全而尝试“锁定”对象。线程安全的应用程序旨在以最少的锁定操作,而不是强制锁定来强制线程安全。

    【讨论】:

    • 这意味着当一个命令完全执行时,只会再次执行第二个命令。那是我不想要的,我想独立执行线程,但是由于TCPClient的锁定,我无法运行不同的线程。
    • 问题不在于 TCP 客户端的锁定。问题是您有一个 TCP 客户端,它维护与服务器的单个连接。如果您想同时执行多个命令,请拥有多个 TCP 客户端,这样您就可以同时进行多个对话。
    • @Yuliy:糟糕的设计选择,使用多个客户端只是为了能够发送多个命令。
    【解决方案2】:

    为每个线程使用一个 TcpClient。

    【讨论】:

    • 这是打开多个 tcpclient 的好方法吗??如果应用程序连接到数据服务器并且还通过它侦听传入消息???
    【解决方案3】:

    首先。当涉及到套接字编程时,锁定是很糟糕的。 @AndrewKeith 的解决方案非常适合对命令进行排队和发送。

    您需要的是有一个请求 ID,您可以将其放入另一个队列并与响应一起发回。通过这样做,您可以拥有多个正在进行的命令。

    简单的伪代码:

    public void Send(ICommand command)
    {
        var myPacket = new CommandPacket {
            Command = command,
            RequestId = Guid.NewGuid()
        };
        _pendingCommands.Add(myPacket);
    
        var buffer = Serialize(myPacket);
        socket.Send(buffer);
    }
    
    public void OnReceive(IAsynResult ar)
    {
        var bytesRead =  socket.EndRecieve(ar);
        _inStream.Write(_readBuffer, 0, bytesRead);
    
        if (GotCompletedPacket(_inStream))
        {
            var packet = Deserialize(_inStream);
            var waitingCommand = _pendingCommands.FirstOrDefault(p => p.RequestId == packet.RequestId);
    
            if (waitingCommand != null)
              //got a reply to the command.
        }
    
    }
    

    我会在调用命令时亲自添加一个委托:

    public void Send(ICommand command, ICommandHandler handler)
    

    并在收到回复时调用该处理程序。

    【讨论】:

      猜你喜欢
      • 2012-05-22
      • 2013-06-05
      • 1970-01-01
      • 2011-10-05
      • 1970-01-01
      • 1970-01-01
      • 2021-11-14
      • 2012-09-20
      • 2015-03-19
      相关资源
      最近更新 更多