2009-12-19 17 views
1
发送多个命令

我想使用中的TcpClient

private TcpClient tcpClient; 

在一类,每一次当我发出这样的命令LISTRETRSTOR,我用来锁住的TcpClient执行的特定时间的命令并获得响应。

现在,当我发送其中一个正在执行的命令时,它不能再锁定该tcpclient实例。

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

回答

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

    } 


} 

你应该试图“锁定”的对象只是为了得到它的线程安全避免的一个例子。线程安全的应用程序设计为以最小的锁定进行操作,而不是强制锁定来强制执行线程安全。

+0

这意味着当一个命令完全执行时,只有第二个命令会再次执行。这就是我不想要的,我想单独执行线程,但由于TCPClient的锁定,我无法运行不同的线程。 – marshalprince 2009-12-19 08:42:06

+2

问题不在于锁定TCP客户端。问题是你有一个单一的TCP客户端,它正在维护与服务器的单一连接。如果您想同时使用多个命令,请使用多个TCP客户端,这样您就可以同时进行多个对话。 – Yuliy 2009-12-19 09:13:31

+0

@Yuliy:糟糕的设计选择使用多个客户端只是为了能够发送几个命令。 – jgauffin 2012-02-03 20:33:19

0

为每个线程使用一个TcpClient。

+0

打开多个tcpclient是否是一种好方法?如果应用程序连接到数据服务器并通过它监听传入消息? – dankyy1 2010-09-13 19:09:12

+0

不是。这是一个很好的解决问题的方法。 – jgauffin 2012-02-03 20:41:19

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) 

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