2010-08-17 2 views
1

Привет, У меня есть пользовательский клиент Telnet на C#. Я использую его для связи с серверами IMAP. Он работает как команда write, а затем получает ответ. Код испытания:Как синхронизировать чтение/запись в поток?

  Telnet tc = new Telnet(); 
      // setup server credentials 
      const string server = "pop.nexlink.net"; 
      const int port = 140; 
      const int timeout = 70; 
      // establish server connection 
      tc.Setup(server, port, timeout); 
      // test initial server response 
      Console.WriteLine(tc.output); 

      // set-up a few commands to send 
      var array = new[] { "USER [email protected]", "PASS password", "QUIT" }; 

      // while connected to server 
      if (tc.IsConnected) 
      { 
       foreach (string str in array) 
       { 
        // Show command on console 
        Console.WriteLine(str); 
        // Write to Stream 
        tc.WriteLine(str); 
        // Read from Stream 
        tc.Read(); 
        // Test the Stream output 
        Console.Write(tc.output); 
       } 


      } 
      // close connection 
      tc.Disconnect(); 

Выход из вызова выше код:

  1. USER [email protected]
  2. + OK Добро пожаловать на сервер POP3 Atmail - Войти пользователь @ домен.
  3. + OK Пароль требуется.
  4. PASS пароль
  5. ВЫЙТИ
  6. + OK вошли в систему.
  7. + OK До свидания.

Это упрощенный пример, однако он показывает проблему состояния гонки. Выход из строки nr.6 должен появиться до nr. 5

В: Как с этим справиться?

+0

Кажется, что все в порядке. Сервер получает сообщение «Выход», прежде чем он завершит вход пользователя в систему. –

+0

Возможно. Ответ довольно случайный. Это зависит от скорости соединения, времени отклика сервера, количества возвращаемых данных. Это становится действительно беспорядочным, когда есть больше команд, каждый из которых запрашивает большие потоки. В целом Чтение происходит намного медленнее, чем Writes. – asyncpro

ответ

0

В прошлом я вручную написал своих клиентов telnet. То, как я обрабатывал команды, заключалось в том, чтобы написать поток для каждой команды, с входами и ожидаемыми ответами (часть ответа, которую я ожидал, в вашем случае + ОК). Это позволит мне отправлять команды и ждать ответа. Если ответ не был получен или не совпал, тогда выполните исключение.

Telnet может отправлять много ответов за команду (пустые, изменение страницы, вход в систему и т. Д.). Поэтому ожидание ожидаемого ответа необходимо.

+0

Это не сработает. Есть много серверов, для которых эта программа должна работать (я в бизнесе интернет-провайдера). Приветствуется более общее решение. Я думал о многопоточности и блокировании ресурсов, но не знаю, как это сделать. – asyncpro

+0

Не видя, как мультисерверная среда не будет работать с этим подходом. Пожалуйста, объясните ... Вы по-прежнему подключены только к одному экземпляру Telnet за раз. Правильно? После того, как я инкапсулирую все необходимые мне команды, я открываю фасад Telnet как службу WCF и управляю пулом подключений к серверу Telenet. – CkH

1

Во-первых, почтовый сервер IMAP не говорит Telnet. Telnet - это протокол поверх TCP. См. RFC 854. Однако добросовестность клиентов Telnet заключается в том, что, поскольку Telnet является очень минимальным протоколом поверх необработанных сокетов TCP, вы можете подключаться и взаимодействовать со многими службами, которые также используют протоколы стиля текстовой команды/ответа поверх TCP (POP3, IMAP, SMTP, HTTP и т. Д.).

В конечном итоге вы должны, вероятно, просто использовать «клиент IMAP на полке». Выполнение некоторых случайных поисков Google привело меня к this one. Я не знаю, хорошо ли это, но это может привести к быстрым победам с вашей стороны.

Если вы хотите научиться правильно работать с сетью TCP/IP, вам необходимо понять некоторые основы двунаправленного ввода-вывода.

Что вы здесь чувствуете, вполне нормально. В сокете TCP есть два канала. Один для чтения, один для написания. Эти каналы независимы и потенциально буферизованы.

Буферизация означает, что только потому, что вы написали некоторые данные (строки или что-то еще) в отправляющий сокет в вашем клиентском коде, это не значит, что он был получен с другого конца.

Поэтому немедленно блокирование чтения после записи может означать, что ваша команда никогда не отправляется, и вы будете блокировать чтение навсегда.

Кроме того, вы можете писать команды в отправляющий сокет так же быстро, как и ваша ОС, и пропускная способность позволит вам. Ответы будут возвращаться всякий раз, когда сервер будет обрабатывать их. Который может быть скоро, а может и никогда.По самой своей сути программирование сокетов является асинхронным и подверженным сбою (вы имеете дело с удаленной системой по ненадежной сети после всего).

Обычный подход при работе с асинхронным двунаправленным IO состоит в том, чтобы иметь два потока. Один для чтения, другой для написания. «Веселье» начинается, когда вам нужно согласовать «чат» запроса & ответ между двумя потоками. Здесь могут помочь примитивы Threading, такие как AutoResetEvent и ManualResetEvent. Хотя вы, вероятно, лучше всего посмотрите на C# Reactive Extensions, поскольку они могут сделать работу намного проще.

В целом я бы предложил reading up on the topic. Написание кода с хорошей ошибкой без сетевого кода является нетривиальным даже для «простых» протоколов, таких как SMTP & POP3.

Если вы не привязаны к использованию C# для своего решения, и вы просто пытаетесь автоматизировать некоторые простые взаимодействия службы Telnet, тогда вы должны посмотреть на утилиту Linux/Unix expect, это может сэкономить вам много времени.

+0

Спасибо, я обязательно проверю все вышеперечисленное. – asyncpro

 Смежные вопросы

  • Нет связанных вопросов^_^