我正在尝试使用
private TcpClient tcpClient;
在一个类中,每当我发送像LIST
,RETR
,STOR
这样的命令时,我曾经在执行命令和获取响应的特定时间锁定TCPClient
现在当我发送另一个命令正在执行时,它无法再次锁定该tcpclient实例。
执行时如何发送其他命令。对于我需要锁定TCPClient的所有命令,我无法更改。
答案 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)
并在收到回复时调用该处理程序。