Отправка нескольких команд в TCPClient - PullRequest
1 голос
/ 19 декабря 2009

Я пытаюсь использовать

private TcpClient tcpClient;

в классе, и каждый раз, когда я отправляю команду типа LIST, RETR, STOR, я использовал для блокировки TCPClient на конкретное время выполнения команд и получения ответа.

Теперь, когда я посылаю другую команду между выполняемой, она не может снова заблокировать этот экземпляр tcpclient.

Как мне отправить другую команду, когда она выполняется. Для всех команд мне нужно заблокировать TCPClient, который я не могу изменить.

Ответы [ 3 ]

2 голосов
/ 19 декабря 2009

Это проблема дизайна. Вам необходимо разработать многопоточный способ доступа к 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 голосов
/ 04 февраля 2012

Прежде всего. Блокировка - это плохо, когда дело доходит до программирования сокетов. Решение @ AndrewKeith хорошо подходит для очередей команд и их отправки.

Вам нужно иметь идентификатор запроса, который вы можете поместить в другую очередь и отправить обратно с ответом. Вы можете сделать несколько текущих команд.

Простой псевдокод:

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)

и вызывать этот обработчик при получении ответа.

0 голосов
/ 19 декабря 2009

Используйте один TcpClient для каждого потока.

...