1

我正在尝试使用

private TcpClient tcpClient;

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

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

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

4

3 回答 3

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);

   }


}

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

于 2009-12-19T08:29:36.507 回答
0

每个线程使用一个 TcpClient。

于 2009-12-19T13:24:05.173 回答
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)

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

于 2012-02-03T20:40:18.793 回答