WCF: ответ клиенту задерживается при передаче файла на сервер с TransferMode = Streamed через netTcpBinding

Я использую потоковую передачу WCF для передачи файла из клиента WCF в службу с помощью netTcpBinding.

Как только клиент вызовет службу с помощью экземпляра Stream, служба начнет чтение из экземпляра Stream через соединение через сокет (StreamConnection). Но, если в процедуре чтения из потока на стороне сервиса возникает исключение, клиентская сторона не может сразу получить исключение.

Я обнаружил период задержки, связанный с sendTimeout привязки. Если я установлю sendTimeout=20 seconds, клиент получит исключение с задержкой в ​​20 секунд; и если sendTimeout = 1 second, клиент немедленно получает исключение.

Я провел небольшое исследование. Насколько я понимаю, даже когда исключение выдается службе, оно не будет выдано клиенту до истечения времени StreamConnection.Read()/StreamConnection.Write(). Этот период ожидания выглядит синхронизированным с привязкой sendTimeout.

Можно ли сохранить sendTimeout и позволить клиенту немедленно получить исключение?

Вот привязка службы, (Чтобы передать файл большого размера, я меняю значение maxReceivedMessageSize, sendTimeout и ReceiveTimeout и т. д.)

  <netTcpBinding>
    <binding  name="StreamingNetTCPBinding" transferMode="Streamed" maxConnections="500" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" sendTimeout="00:45:00" receiveTimeout="23:00:00" listenBacklog="20">
      <readerQuotas maxArrayLength="2147483647" maxDepth="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" maxStringContentLength="2147483647" />
    </binding>
  </netTcpBinding>

person user1256475    schedule 01.07.2013    source источник
comment
У кого-нибудь есть идеи?   -  person user1256475    schedule 01.07.2013


Ответы (1)


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

У вас есть несколько вариантов того, как с этим справиться, в зависимости от ваших требований, большинство из которых потребует изменения только кода службы. На стороне службы, если у вас возникло исключение, вам нужно поймать исключение, слить входящий поток, а затем повторно создать исключение, которое приведет к возврату сообщения об ошибке. Поскольку поток ответа был полностью прочитан, клиент завершил всю отправку и теперь ожидает ответа. Это требует отправки всего потока запросов, и в случае преждевременного отказа большого запроса это может быть нежелательно. Если нежелательно тратить время/пропускную способность на получение остальной части сообщения, вы можете сломать канал (используя Abort()) на стороне службы. Это приведет к отключению сокета, и вы получите исключение CommunicationException на стороне клиента. Недостаток этого в том, что вы не получаете информацию о том, что пошло не так, но это происходит довольно быстро.

Другой вариант, который требует изменений на стороне клиента и сервера, — это использование двух каналов и использование второго канала для получения OOB-информации о статусе запроса по первому каналу.

person MattC    schedule 13.04.2016