在TCPClient中发送多个命令

时间:2009-12-19 08:14:14

标签: c# .net tcpclient

我正在尝试使用

private TcpClient tcpClient;

在一个类中,每当我发送像LISTRETRSTOR这样的命令时,我曾经在执行命令和获取响应的特定时间锁定TCPClient

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

执行时如何发送其他命令。对于我需要锁定TCPClient的所有命令,我无法更改。

3 个答案:

答案 0 :(得分:2)

这是一个设计问题。您需要设计一种多线程方式来访问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);

   }


}

你应该避免试图“锁定”对象只是为了让它具有线程安全性。线程安全的应用程序旨在以最小的锁定操作,而不是强制锁定来强制执行线程安全。

答案 1 :(得分:0)

为每个线程使用一个TcpClient。

答案 2 :(得分:0)

首先。在套接字编程方面,锁定都很糟糕。 @ 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)

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