我正在尝试使用
private TcpClient tcpClient;
在课堂上,每次我发送类似LIST
, RETR
,的命令时STOR
,我都会在执行命令和获得响应的特定时间锁定 TCPClient。
现在,当我在执行之间发送另一个命令时,它无法再次锁定该 tcpclient 实例。
当一个命令正在执行时,我应该如何发送另一个命令。对于我需要锁定 TCPClient 的所有命令,我无法更改。
这是一个设计问题。您需要设计一种访问 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。
首先。当涉及到套接字编程时,锁定是很糟糕的。@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)
并在收到回复时调用该处理程序。