Как синхронизировать чтение / запись в поток? - PullRequest
1 голос
/ 17 августа 2010

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

            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 AppChecker@nexlink.net", "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 AppChecker@nexlink.net
  2. + OK Добро пожаловать на сервер Atmail POP3 - войдите с помощью user@domain.
  3. + OK Требуется пароль.
  4. пароль PASS
  5. QUIT
  6. + OK вошли в систему.
  7. + ОК Пока.

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

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

Ответы [ 2 ]

1 голос
/ 17 августа 2010

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

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

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

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

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

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

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

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

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

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

0 голосов
/ 17 августа 2010

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

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

...