Транспорт: TCP-взаимодействие WSE 3.0
В примере транспорта взаимодействия TCP WSE 3.0 показано, как реализовать дуплексный сеанс TCP в качестве настраиваемого транспорта Windows Communication Foundation (WCF). Также демонстрируется использование расширяемости уровня канала для создания интерфейса по сети с существующими развернутыми системами. Ниже показано, как создать этот пользовательский транспорт WCF:
Начиная с сокета TCP, создайте клиентские и серверные реализации интерфейса IDuplexSessionChannel, использующие кадрирование DIME для разграничения границ сообщений.
Создайте фабрику каналов, которая подключается к службе TCP WSE и передает кадрированные сообщения через клиентские интерфейсы IDuplexSessionChannel.
Создайте прослушиватель канала для приема входящих подключений TCP и создания соответствующих каналов.
Убедитесь, что все исключения, связанные с сетью, нормализованы в соответствующий класс, унаследованный от CommunicationException.
Добавьте элемент привязки, добавляющий пользовательский транспорт в стек каналов. Дополнительные сведения см. в разделе [Добавление элемента привязки].
Создание IDuplexSessionChannel
Первый этап создания транспорта взаимодействия TCP WSE 3.0 - это реализация интерфейса IDuplexSessionChannel на основе класса Socket. WseTcpDuplexSessionChannel
является производным от ChannelBase. Логика передачи сообщения состоит из двух основных частей: (1) кодирование сообщения в байты и (2) кадрирование этих байтов и передача их по сети.
ArraySegment<byte> encodedBytes = EncodeMessage(message);
WriteData(encodedBytes);
Кроме того, устанавливается блокировка, чтобы вызовы Send() сохраняли гарантию порядка IDuplexSessionChannel и чтобы вызовы соответствующего сокета были правильно синхронизированы.
WseTcpDuplexSessionChannel
использует MessageEncoder для преобразования Message в массив byte[] и из него. Так как это транспорт, канал WseTcpDuplexSessionChannel
также отвечает за использование удаленного адреса, с которым был настроен канал. EncodeMessage
инкапсулирует логику для этого преобразования.
this.RemoteAddress.ApplyTo(message);
return encoder.WriteMessage(message, maxBufferSize, bufferManager);
После того как сообщение Message закодировано в байты, оно должно быть передано по сети. Для этого требуется система определения границ сообщения. WSE 3.0 использует версию DIME в качестве протокола обрамления. WriteData
инкапсулирует логику кадрирования для заключения массива byte[] в набор записей DIME.
Логика получения сообщений аналогична. Основная сложность заключается в том, что чтение сокета может возвращать меньше байтов, чем запрошено. Чтобы принять сообщение, WseTcpDuplexSessionChannel
считывает байты из сети, декодирует кадрирование DIME, затем использует MessageEncoder для преобразования массива byte[] в сообщение Message.
Базовый класс WseTcpDuplexSessionChannel
предполагает, что он получает подключенный сокет. Базовый класс обрабатывает завершение работы сокета. Существуют три места, взаимодействующих с закрытием сокета:
OnAbort - закрыть сокет некорректно (жесткое закрытие).
On[Begin]Close - закрыть сокет корректно (мягкое закрытие).
Сессии. CloseOutputSession — завершите исходящий поток данных (половина закрытия).
Фабрика каналов
Следующий этап создания транспорта TCP - реализация IChannelFactory для каналов клиентов.
WseTcpChannelFactory
производный от ChannelFactoryBase<IDuplexSessionChannel>. Это фабрика, которая переопределяетOnCreateChannel
для создания каналов клиентов.
protected override IDuplexSessionChannel OnCreateChannel(EndpointAddress remoteAddress, Uri via)
{
return new ClientWseTcpDuplexSessionChannel(encoderFactory, bufferManager, remoteAddress, via, this);
}
ClientWseTcpDuplexSessionChannel
добавляет логику в базуWseTcpDuplexSessionChannel
для подключения к TCP-серверу воchannel.Open
время. Сначала имя узла разрешается в IP-адрес, как показано в следующем коде.
hostEntry = Dns.GetHostEntry(Via.Host);
- Затем имя узла подключается в цикле к первому доступному IP-адресу, как показано в следующем коде.
IPAddress address = hostEntry.AddressList[i];
socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(new IPEndPoint(address, port));
- Как часть контракта канала, все специфичные для домена расширения заключаются в оболочку, как
SocketException
в CommunicationException.
Прослушиватель канала
Следующий этап создания транспорта TCP - реализация IChannelListener для приема каналов сервера.
WseTcpChannelListener
является производным от ChannelListenerBase<IDuplexSessionChannel> и переопределяет On[Begin]Open and On[Begin]Close, чтобы управлять временем существования его сокета прослушивания. В OnOpen создается сокет для прослушивания по IP_ANY. Более сложные реализации могут создавать второй сокет для прослушивания также и по IPv6. Они могут также допускать задание IP-адреса в имени узла.
IPEndPoint localEndpoint = new IPEndPoint(IPAddress.Any, uri.Port);
this.listenSocket = new Socket(localEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
this.listenSocket.Bind(localEndpoint);
this.listenSocket.Listen(10);
Когда принимается новый сокет, инициализируется новый канал сервера с этим сокетом. Все операции ввода и вывода уже реализованы в базовом классе, поэтому этот канал отвечает за инициализацию сокета.
Добавление элемента привязки
Теперь, когда фабрики и каналы построены, они должны быть предоставлены среде выполнения ServiceModel через привязку. Привязка - это коллекция элементов привязки, представляющая стек связи для адреса службы. Каждый элемент стека представлен элементом привязки.
В этом примере в качестве элемента привязки выступает элемент WseTcpTransportBindingElement
, являющийся производным элемента TransportBindingElement. Он поддерживает IDuplexSessionChannel и переопределяет следующие методы создания фабрик, связанных с нашей привязкой.
public IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
{
return (IChannelFactory<TChannel>)(object)new WseTcpChannelFactory(this, context);
}
public IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
{
return (IChannelListener<TChannel>)(object)new WseTcpChannelListener(this, context);
}
Он также содержит члены для клонирования элемента BindingElement
и возврата схемы (wse.tcp).
Тестовая консоль WSE TCP
Тестовый код для использования этого образца транспорта находится в файле TestCode.cs. Ниже показано, как выполнить построение и запуск образца TcpSyncStockService
.
Тестовый код создает пользовательскую привязку, которая использует MTOM для кодирования и WseTcpTransport
для транспорта. Он также настраивает AddressingVersion для соответствия WSE 3.0, как показано в следующем примере кода.
CustomBinding binding = new CustomBinding();
MtomMessageEncodingBindingElement mtomBindingElement = new MtomMessageEncodingBindingElement();
mtomBindingElement.MessageVersion = MessageVersion.Soap11WSAddressingAugust2004;
binding.Elements.Add(mtomBindingElement);
binding.Elements.Add(new WseTcpTransportBindingElement());
Он состоит из двух тестов - один тест настраивает типизированного клиента с помощью кода, созданного из WSE 3.0 WSDL. Второй тест использует WCF как клиент, так и сервер, отправляя сообщения непосредственно на вершине API каналов.
При выполнении этого образца ожидаются следующие выходные данные.
Клиент:
Calling soap://stockservice.contoso.com/wse/samples/2003/06/TcpSyncStockService
Symbol: FABRIKAM
Name: Fabrikam, Inc.
Last Price: 120
Symbol: CONTOSO
Name: Contoso Corp.
Last Price: 50.07
Press enter.
Received Action: http://SayHello
Received Body: to you.
Hello to you.
Press enter.
Received Action: http://NotHello
Received Body: to me.
Press enter.
Сервер:
Listening for messages at soap://stockservice.contoso.com/wse/samples/2003/06/TcpSyncStockService
Press any key to exit when done...
Request received.
Symbols:
FABRIKAM
CONTOSO
Настройка, сборка и запуск примера
- Чтобы запустить этот пример, необходимо иметь улучшения веб-служб (WSE) 3.0 для Microsoft .NET и установленный пример WSE
TcpSyncStockService
.
Примечание.
Так как WSE 3.0 не поддерживается в Windows Server 2008, вы не можете установить или запустить TcpSyncStockService
пример в этой операционной системе.
После установки примера
TcpSyncStockService
выполните следующие операции.TcpSyncStockService
Откройте visual Studio. (The Пример TcpSyncStockService устанавливается с WSE 3.0. Это не является частью кода этого примера.)Задайте проект StockService в качестве начального проекта.
Откройте файл StockService.cs в проекте StockService и закомментируйте атрибут [Policy] класса
StockService
. Таким образом в примере отключается безопасность. Хотя WCF может взаимодействовать с безопасными конечными точками WSE 3.0, безопасность отключена, чтобы сохранить этот пример сосредоточен на пользовательском tcp-транспорте.Нажмите клавишу F5 , чтобы запустить
TcpSyncStockService
. Служба запускается в новом окне консоли.Откройте пример транспорта TCP в Visual Studio.
Обновите переменную "hostname" в файле TestCode.cs, чтобы она соответствовала имени компьютера, на котором запущена служба
TcpSyncStockService
.Нажмите клавишу F5 , чтобы запустить образец транспорта TCP.
Тестовый клиент транспорта TCP запускается в новой консоли. Клиент запрашивает у службы цены акций и отображает результаты в своем окне консоли.