Чтение () проблема блокировки

2

Я разрабатываю серверное приложение на С#. Клиенты могут подключаться к серверу и выполнять различные запросы. В настоящее время, когда клиент подключается, я создаю новый поток для обработки запросов (запросов). Я использую класс TCPClient для обработки клиентских подключений. Мой сервер работает следующим образом:

  • Клиент подключается к серверу с запросом
  • Сервер обрабатывает запрос
  • Сервер ожидает, будет ли у клиента больше запросов
  • Если клиент не делает другого запроса в течение некоторого периода ожидания, сервер убивает соединение

Моя проблема заключается в следующем:

Когда я прочитаю из объекта NetworkStream, который я получаю из класса TCPClient, метод NetworkStream Read() не блокирует, если нет доступных данных. Когда сервер достигает шага №3, я хотел бы установить некоторый тайм-аут в NetworkStream, и если клиент не сделает больше запросов в течение этой продолжительности, сервер должен убить соединение, когда будет выбрано это исключение таймаута. Когда мой сервер достигает шага 3, метод NetworkStream Read() не блокирует, независимо от того, что я установил для него свойство ReadTimeout. Может ли кто-нибудь помочь мне или предложить лучший способ сделать то, что я пытаюсь сделать.

Спасибо

  • 1
    Не могли бы вы вместо этого использовать UDP и сделать его без установления соединения?
Теги:
tcpclient

6 ответов

2

NetworkStream.Read и ReadByte должны блокироваться до таймаута, если нет данных для чтения. Я думаю, что гораздо более вероятно, что звонок что-то читает, вероятно, пучок нулей. Проверьте данные, отправляемые клиентом тщательно.

  • 0
    Я думаю точно так же.
0

Чтобы принудительно заблокировать NetworkStream, когда нет доступных данных:

TcpClient clientConnection = new TcpClient();

if(clientConnection.Available > 0)
{ 
  //You want to continue execution even though there is no available data to be read from the server then:
  clientConnection.Client.Blocking = false;
}
0

Это то, что вы ищете?

http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.receivetimeout.aspx

Похоже, вы получаете NetworkStream из TcpClient с помощью GetStream(), а затем вызываете метод Read() на нем.

0

Оберните NetworkStream в BufferedStream. BufferedStream.Read будет блокироваться, пока не будет доступно по крайней мере 1 байт.

  • 0
    Кажется, что я не могу установить время ожидания для BufferedStream, обернутого вокруг NetworkStream (System.InvalidOperationException: Таймауты не поддерживаются в этом потоке ...) Таким образом, мне все равно придется обрабатывать тайм-аут вручную, если я пошел по этому маршруту
  • 0
    Настройте таймеры для обработки тайм-аутов. когда таймер закрывает сокет, в методе чтения будет выдано исключение. Затем, когда данные прочитаны, сбросьте таймер.
0

Вам потребуется обработать "тайм-аут" самостоятельно, так как NetworkStream.Read() не предоставляет способ сделать это.

То, что вы, вероятно, захотите сделать в потоке клиента, - это использование некоторой комбинации NetworkStream.DataAvailable и/или NetworkStream.CanRead в сочетании с механизмом блокировки/тайм-аута (например, с использованием вызова WaitHandle.WaitOne с таймаутом) чтобы предоставить клиенту время для предоставления данных. Если через определенное время ничего не приходит, просто выключите соединение и выйдите.

  • 0
    Гм. msmvps.com/blogs/peterritchie/archive/2007/04/26/...
  • 0
    Я не всегда согласен с аргументами Питера Ричи, особенно в пользовательских темах. Он даже (в обсуждении) выступает за использование Thread.Sleep (1) в некоторых случаях. При этом, в данном случае, я думаю, что использование WaitHandle, вероятно, является лучшим дизайном, поэтому я изменил свой ответ.
Показать ещё 5 комментариев
0

Вы должны прекратить использование метода Read() для метода BeginRead() и изучить параллельную обработку. Сетевое программирование не для слабонервных.

В принципе, вы не хотите создавать опрос циклов для данных.

while(!timedout && !stream.DataAvailable) sleep(0); // This is bad.
if(steam.DataAvailable) steam.Read();

Вместо этого имеет смысл делать что-то подобное. Создайте событие reset, вызовите BeginRead() и отпустите событие reset в обратном вызове. Что-то вроде следующего:

void clientThread()
{
   stream.BeginRead(myCallback);
   resetEvent.WaitOne(timeout)
}
void myCallback
{
   resetEvent.Set();
}
  • 1
    Он уже создает новый поток для каждого клиента, и в этом случае использование BeginRead имеет меньше смысла ....
  • 0
    Это имеет больше смысла, чем использование сна. msmvps.com/blogs/peterritchie/archive/2007/04/26/...
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню