Подтвердить что ты не робот

Как прервать поток из службы WCF, не прочитав его до конца?

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

У меня есть служба WCF, которая возвращает объект, содержащий stream внутри него. Я использую basicHttpBinding с потоковой передачей и Mtom, чтобы отправить его клиенту.

Клиент вызывает службу WCF и закрывает прокси сразу после получения объекта ответа.

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

Моя проблема в том, когда клиент хочет прервать операцию и прекратить загрузку данных из службы WCF. Если я вызываю .close() в потоке, например: serverReply.DataStream.Close();, тогда он блокирует и читает весь поток из службы WCF до его конца, прежде чем продолжить. Поток может быть довольно большим, и сеть не всегда быстрая.

Это очень нежелательно для использования сетевых ресурсов, что в основном напрасно тратится на данные, которые больше не нужны. А поскольку basicHttpBinding допускает только два параллельных TCP-соединения (по умолчанию) к серверу службы WCF, он блокирует другие попытки подключения до тех пор, пока поток не будет прочитан до конца.

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

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

На клиенте объект потока является обычным stream классом, поэтому он имеет только метод close, и ничего больше.

Вызов .close() или .abort() на прокси-объекте не помогает, а также не уничтожает его с помощью .dispose() или любого другого метода. На стороне сервера я обрабатываю событие OperationContext.OperationCompleted, но он не запускается до тех пор, пока данные из stream не будут прочитаны до конца.

Итак, вопрос в том, как закрыть/прервать поток, не прочитав его полностью?

4b9b3361

Ответ 1

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

ПРИМЕЧАНИЕ. Вы должны обернуть код, который предоставляет поток в блок try/catch. Метод stream.Dispose() будет вызывать TimeoutException, который тормозит директиву не выдавая исключений в методе Dispose.

Ответ 2

Вы пытались играть с binding.MaxBufferSize?
Вы пытались играть с настройками файла app.config, например:

<bindings>
  <wsHttpBinding>
    <binding name="default" maxReceivedMessageSize="2147483647"  maxBufferPoolSize="2147483647" 
             closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" >
      <readerQuotas  maxArrayLength="2147483647" maxBytesPerRead="4096" maxNameTableCharCount="16384"
                     maxDepth="64" maxStringContentLength="2147483647" />
    </binding>

  </wsHttpBinding>
</bindings>

Я бы минимизировал тайм-ауты длины буфера и попытался прервать или закрыть и посмотреть, что произойдет.

Ответ 3

Я думаю, что вы просто получаете буфер после закрытия. Вы должны установить maxBufferSize на меньшее значение.

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

Мои собственные тесты по этой теме включали в себя запись NeverEndingStream и возвращение данных всегда. В какой-то момент я позвонил близко к клиенту, и почти сразу же вызов был вызван на сервере. Это говорит о том, что буфер был просто опустошен, потому что, очевидно, он никогда не сможет прочитать мой поток до конца.

Если вы все еще испытываете проблемы, я предлагаю вам отслеживать время метода Read на вашем переопределенном потоке. Если currentReadtime - lastReadTime > x, то вместо этого вы можете вызвать Close и выставить исключение. Это наверняка убьет его.