Поделиться через


Поток

В примере Stream демонстрируется использование обмена данными в режиме потоковой передачи. Служба предоставляет несколько операций, которые отправляют и получают потоки. Этот пример размещен самостоятельно. Как клиент, так и служба являются консольными программами.

Замечание

Процедура установки и инструкции по сборке для этого примера находятся в конце этого раздела.

Windows Communication Foundation (WCF) может взаимодействовать в двух режимах передачи — буферизованной или потоковой передаче. В режиме буферизованной передачи по умолчанию сообщение должно быть полностью доставлено, прежде чем получатель сможет прочитать его. В режиме потоковой передачи получатель может начать обрабатывать сообщение до его полного доставки. Режим потоковой передачи полезен, если передаваемые сведения являются длительными и могут быть последовательно обработаны. Режим потоковой передачи также полезен, если сообщение слишком велико, чтобы быть полностью буферизованно.

Контракты потоковой передачи и службы

Стриминг — это то, что следует учитывать при разработке контракта на предоставление услуг. Если операция получает или возвращает большие объемы данных, следует рассмотреть возможность потоковой передачи этих данных, чтобы избежать высокой загрузки памяти из-за буферизации входных или выходных сообщений. Для потоковой передачи данных параметр, содержащий эти данные, должен быть единственным параметром в сообщении. Например, если входное сообщение — это тот, который должен быть передан, операция должна иметь ровно один входной параметр. Аналогичным образом, если выходное сообщение должно быть потоково, операция должна иметь либо ровно один выходной параметр, либо возвращаемое значение. В любом случае параметр или возвращаемый тип значения должен быть Streamлибо , Messageлибо IXmlSerializable. Ниже приведен контракт службы, используемый в этом примере потоковой передачи.

[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IStreamingSample
{
    [OperationContract]
    Stream GetStream(string data);
    [OperationContract]
    bool UploadStream(Stream stream);
    [OperationContract]
    Stream EchoStream(Stream stream);
    [OperationContract]
    Stream GetReversedStream();

}

Операция GetStream получает некоторые входные данные в виде строки, которая буферизована, и возвращает Stream, который является потоковым объектом. И наоборот, UploadStream принимает потоковые данные (Stream) и возвращает буферизованные данные (bool). EchoStream принимает и возвращает Stream и является примером операции, входные и выходные сообщения которой передаются в виде потока. GetReversedStream не принимает входных данных и возвращает Stream в потоковом формате.

Включение потоковой передачи

Определение контрактов операций, как описано ранее, обеспечивает потоковую передачу на уровне модели программирования. Если остановиться там, транспорт по-прежнему буферизирует весь контент сообщения. Чтобы включить потоковую передачу транспорта, выберите режим передачи в элементе привязки транспорта. Свойству TransferMode элемента привязки можно присвоить значение Buffered, Streamed, StreamedRequest или StreamedResponse. Если режиму передачи присвоено значение Streamed, потоковая передача будет выполняться в обоих направлениях. Установка режима передачи на StreamedRequest или StreamedResponse позволяет потоковую передачу данных только в запросе или только в ответе соответственно.

basicHttpBinding предоставляет свойство TransferMode на привязке, как это делают NetTcpBinding и NetNamedPipeBinding. Для других транспортов необходимо создать пользовательскую привязку для задания режима передачи.

В следующем примере кода конфигурации показано, как задать свойство TransferMode для включения потоковой передачи на basicHttpBinding и в пользовательской привязке HTTP.

<!-- An example basicHttpBinding using streaming. -->
<basicHttpBinding>
  <binding name="HttpStreaming" maxReceivedMessageSize="67108864"
           transferMode="Streamed"/>
</basicHttpBinding>
<!-- An example customBinding using HTTP and streaming.-->
<customBinding>
  <binding name="Soap12">
    <textMessageEncoding messageVersion="Soap12WSAddressing10" />
    <httpTransport transferMode="Streamed"
                   maxReceivedMessageSize="67108864"/>
  </binding>
</customBinding>

Помимо задания transferMode в Streamed, предыдущий код конфигурации задает maxReceivedMessageSize значение 64 МБ. В качестве механизма защиты maxReceivedMessageSize устанавливает ограничение на максимальный допустимый размер сообщений при их получении. Значение по умолчанию maxReceivedMessageSize — 64 КБ, которое обычно слишком низко для сценариев потоковой передачи.

Обработка данных в режиме потоковой передачи

Операции GetStream, UploadStream и EchoStream выполняют действия по отправке данных непосредственно из файла или сохранению полученных данных непосредственно в файл. Однако в некоторых случаях требуется отправить или получить большие объемы данных и выполнить некоторую обработку на блоках данных по мере отправки или получения. Один из способов решения таких сценариев заключается в написании пользовательского потока (класса, наследуемого от Stream), обрабатывающего данные по мере чтения или записи. Операция GetReversedStream и ReverseStream класс являются примером этого.

GetReversedStream создает и возвращает новый экземпляр ReverseStream. Фактическая обработка происходит, когда система считывает из этого ReverseStream объекта. Реализация ReverseStream.Read считывает фрагмент байтов из базового файла, изменяет их, а затем возвращает обратные байты. Это не отменяет весь контент файла; Он изменяет один блок байтов за раз. В этом примере показано, как выполнять обработку потоков при считывании и записи содержимого в поток и из него.

class ReverseStream : Stream
{

    FileStream inStream;
    internal ReverseStream(string filePath)
    {
        //Opens the file and places a StreamReader around it.
        inStream = File.OpenRead(filePath);
    }

    // Other methods removed for brevity.

    public override int Read(byte[] buffer, int offset, int count)
    {
        int countRead=inStream.Read(buffer, offset,count);
        ReverseBuffer(buffer, offset, countRead);
        return countRead;
    }

    public override void Close()
    {
        inStream.Close();
        base.Close();
    }
    protected override void Dispose(bool disposing)
    {
        inStream.Dispose();
        base.Dispose(disposing);
    }
    void ReverseBuffer(byte[] buffer, int offset, int count)
    {
        int i, j;
        for (i = offset, j = offset + count - 1; i < j; i++, j--)
        {
            byte currenti = buffer[i];
            buffer[i] = buffer[j];
            buffer[j] = currenti;
        }

    }
}

Запуск тестового примера

Чтобы запустить пример, сначала создайте службу и клиент, следуя указаниям в конце этого документа. Затем запустите службу и клиент в двух разных окнах консоли. Когда клиент запускается, он ожидает нажатия клавиши ВВОД, когда служба будет готова. Затем клиент вызывает методы GetStream()UploadStream() и GetReversedStream() сначала по протоколу HTTP, а затем по протоколу TCP. Ниже приведен пример выходных данных из службы, за которым следует пример выходных данных клиента:

Выходные данные службы:

The streaming service is ready.
Press <ENTER> to terminate service.

Saving to file D:\...\uploadedfile
......................
File D:\...\uploadedfile saved
Saving to file D:\...\uploadedfile
...............
File D:\...\uploadedfile saved

Выходные данные клиента:

Press <ENTER> when service is ready
------ Using HTTP ------
Calling GetStream()
Saving to file D:\...\clientfile
......................
Wrote 33405 bytes to stream

File D:\...\clientfile saved
Calling UploadStream()
Calling GetReversedStream()
Saving to file D:\...\clientfile
......................
Wrote 33405 bytes to stream

File D:\...\clientfile saved
------ Using Custom HTTP ------
Calling GetStream()
Saving to file D:\...\clientfile
...............
Wrote 33405 bytes to stream

File D:\...\clientfile saved
Calling UploadStream()
Calling GetReversedStream()
Saving to file D:\...\clientfile
...............
Wrote 33405 bytes to stream

File D:\...\clientfile saved

Press <ENTER> to terminate client.

Настройка, сборка и запуск примера

  1. Убедитесь, что вы выполнили процедуру настройки One-Time для образцов Windows Communication Foundation.

  2. Чтобы создать версию решения на C# или Visual Basic .NET, следуйте инструкциям по сборке примеров Windows Communication Foundation .

  3. Чтобы запустить пример в конфигурации с одним или несколькими компьютерами, следуйте инструкциям в запуска примеров Windows Communication Foundation.

Замечание

Если вы используете Svcutil.exe для повторного создания конфигурации для этого примера, обязательно измените имя конечной точки в конфигурации клиента, чтобы соответствовать коду клиента.