Транспорт: UDP
В примере транспорта UDP показано, как реализовать одноадресную рассылку UDP и многоадресную рассылку в качестве настраиваемого транспорта Windows Communication Foundation (WCF). В примере описана рекомендуемая процедура создания пользовательского транспорта в WCF с помощью платформы каналов и рекомендаций WCF. Для создания пользовательского транспорта выполните следующие действия.
Определите, какие из шаблонов обмена сообщениями канала (IOutputChannel, IInputChannel, IDuplexChannel, IRequestChannel или IReplyChannel) будут поддерживать channelFactory и ChannelListener. Затем решите, поддерживать ли связанные с сеансами разновидности указанных интерфейсов.
Создайте фабрику и прослушиватель каналов, которые поддерживают выбранный шаблон обмена сообщениями.
Убедитесь, что все исключения, связанные с сетью, нормализованы в соответствующий класс, унаследованный от CommunicationException.
<Добавьте элемент привязки>, который добавляет пользовательский транспорт в стек каналов. Дополнительные сведения см. в разделе "Добавление элемента привязки".
Добавьте раздел расширения элементов привязки, чтобы представить новый элемент привязки системе конфигурации.
Добавьте расширения метаданных, чтобы сообщить о возможностях в другие конечные точки.
Добавьте привязку, которая предварительно настраивает стек элементов привязки в соответствии с четко определенным профилем. Дополнительные сведения см. в разделе "Добавление стандартной привязки".
Добавьте раздел привязки и элемент конфигурации привязки, чтобы представить привязку системе конфигурации. Дополнительные сведения см. в разделе "Добавление поддержки конфигурации".
Шаблоны обмена сообщениями
При создании пользовательского транспорта в первую очередь решите, какие шаблоны обмена сообщениями требуются для транспорта. Можно выбирать из трех шаблонов обмена сообщениями.
Датаграмма (IInputChannel/IOutputChannel)
При использовании шаблона обмена сообщениями "датаграмма" клиент отправляет сообщения, используя принцип "отправить и забыть". В этом случае требуется внешнее подтверждение успешной доставки. Сообщение может быть потеряно при передаче и может не достичь службы. Если операция отправки успешно выполняется на стороне клиента, это не гарантирует, что удаленная конечная точка получит сообщение. Датаграмма - фундаментальный элемент обмена сообщениями, на основе которого можно строить собственные протоколы, в том числе надежные и безопасные. Каналы датаграмм клиентов реализуют интерфейс IOutputChannel, а каналы датаграмм служб - интерфейс IInputChannel.
Запрос-ответ (IRequestChannel/IReplyChannel)
При использовании этого шаблона происходит отправка сообщения и получение ответа. Шаблон состоит из пар «запрос-ответ». Примеры вызовов "запрос-ответ" - удаленные вызовы процедур и запросы GET браузера. Этот шаблон также называют полудуплексным. При использовании этого шаблона обмена сообщениями каналы клиентов реализуют интерфейс IRequestChannel, а каналы служб - интерфейс IReplyChannel.
Дуплекс (IDuplexChannel)
Дуплексный шаблон обмена сообщениями позволяет клиенту отправлять произвольное количество сообщений и принимать их в произвольном порядке. Применение дуплексного шаблона похоже на разговор по телефону, когда каждое произносимое слово является сообщением. Поскольку в данном случае принимать и отправлять сообщения могут обе стороны, каналы клиента и службы реализуют интерфейс IDuplexChannel.
Каждый из этих шаблонов обмена сообщениями также поддерживает сеансы. Канал, поддерживающий сеансы, содержит функции для согласования всех сообщений, отправляемых и принимаемых через канал. Шаблон "запрос-ответ" является отдельным сеансом из двух сообщений, поскольку запрос и ответ связаны друг с другом. В отличие от него в поддерживающем сеансы шаблоне "запрос-ответ" предполагается, что все пары "запрос-ответ" в канале связаны друг с другом. Таким образом, можно выбирать один из шести шаблонов: датаграмма, "запрос-ответ", дуплекс, датаграмма с поддержкой сеансов, "запрос-ответ" с поддержкой сеансов и дуплекс с поддержкой сеансов.
Примечание.
Для транспорта по протоколу UDP единственным поддерживаемым шаблоном обмена сообщениями является датаграмма, поскольку структура протокола UDP основана на принципе "отправить и забыть".
Жизненный цикл ICommunicationObject и объектов WCF
WCF имеет общий компьютер состояния, используемый для управления жизненным циклом объектов, таких как IChannel, IChannelFactoryи IChannelListener используемых для обмена данными. Эти объекты взаимодействий могут находиться в пяти состояниях. Эти состояния, приведенные ниже, представлены перечислением CommunicationState.
Создано: это состояние первого экземпляра ICommunicationObject . Ввод и вывод в этом состоянии не происходит.
Открытие: объекты переходить к этому состоянию при Open вызове. В этот момент свойства перестают быть изменяемыми, и могут начинаться ввод и вывод. Переход в это состояние возможен только из состояния Created.
Opened: в это состояние объекты переходят по окончании процесса открытия. Переход в это состояние возможен только из состояния Opening. С этого момента объект полностью пригоден для передачи сообщений.
Закрытие: объекты переходить к этому состоянию при Close вызове корректного завершения работы. Переход в это состояние возможен только из состояния Opened.
Closed: в состоянии Closed объекты использовать нельзя. В общем случае большинство конфигураций доступны для изучения, но никакие взаимодействия происходить не могут. Это состояние равнозначно удалению.
Faulted: в состоянии Faulted объекты доступны для изучения, но их нельзя использовать. Объекты переходят в это состояние при возникновении неустранимой ошибки. Единственным допустимым переходом из этого состояния является
Closed
состояние.
Есть события, возникающие при каждом изменении состояния. Метод Abort можно вызывать в любое время и вызывать объект немедленно из текущего состояния в закрытое состояние. Вызов Abort прекращает любую незаконченную работу.
Фабрика каналов и прослушиватель каналов
Следующий этап создания пользовательского транспорта - реализация IChannelFactory для каналов клиентов и IChannelListener для каналов служб. Уровень канала использует шаблон фабрики для создания каналов. WCF предоставляет вспомогательные средства базового класса для этого процесса.
Класс CommunicationObject реализует интерфейс ICommunicationObject и принудительно создает конечный автомат, описанный ранее на шаге 2.
Класс ChannelManagerBase реализует CommunicationObject и предоставляет единый базовый класс для ChannelFactoryBase и ChannelListenerBase. Класс ChannelManagerBase работает совместно с классом ChannelBase - базовым классом, реализующим интерфейс IChannel.
Класс ChannelFactoryBase реализует ChannelManagerBase и IChannelFactory объединяет
CreateChannel
перегрузки в одинOnCreateChannel
абстрактный метод.Класс ChannelListenerBase реализует IChannelListener. Он отвечает за базовое управление состоянием.
В этом образце реализация фабрики содержится в UdpChannelFactory.cs, а реализация прослушивателя содержится в UdpChannelListener.cs. Реализации IChannel находятся в UdpOutputChannel.cs и UdpInputChannel.cs.
Фабрика канала UDP
ФабрикаUdpChannelFactory
наследуется от класса ChannelFactoryBase. В образце переопределяется метод GetProperty для обеспечения доступа к версии сообщения кодировщика сообщений. Также переопределяется метод OnClose, позволяющий убрать созданный экземпляр класса BufferManager при переходе конечного автомата в другое состояние.
Выходной канал UDP
КлассUdpOutputChannel
реализует интерфейс IOutputChannel. Конструктор проверяет аргументы и создает целевой объект EndPoint на основании переданного ему адреса EndpointAddress.
this.socket = new Socket(this.remoteEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
Канал может быть закрыт правильно или неправильно. При верном закрытии канала сокет закрывается и вызывается метод OnClose
базового класса. Если при этом создается исключение, инфраструктура вызывает метод Abort
, чтоб обеспечить очистку канала.
this.socket.Close(0);
Затем мы реализуем Send()
и BeginSend()
/EndSend()
. Реализация делится на две принципиальные части. Сначала сообщение сериализуется в байтовый массив.
ArraySegment<byte> messageBuffer = EncodeMessage(message);
Затем получившиеся данные отправляются по сети.
this.socket.SendTo(messageBuffer.Array, messageBuffer.Offset, messageBuffer.Count, SocketFlags.None, this.remoteEndPoint);
Класс UdpChannelListener
Пример UdpChannelListener
реализует производный от ChannelListenerBase класса. Он использует один UDP-сокет для приема датаграмм. Метод OnOpen
принимает данные через UDP-сокет в асинхронном цикле. Затем данные преобразуются в сообщения с помощью системы кодирования сообщений.
message = MessageEncoderFactory.Encoder.ReadMessage(new ArraySegment<byte>(buffer, 0, count), bufferManager);
Поскольку один канал датаграмм представляет сообщения, приходящие из нескольких источников, UdpChannelListener
- одноэлементный прослушиватель. Существует, по крайней мере, одна активная IChannel связь с этим прослушивателем за раз. В образце создается новый экземпляр только в том случае, если канал, возвращенный методом AcceptChannel
, был впоследствии освобожден. Когда сообщение принято, оно ставится в очередь в этот одноэлементный канал.
UdpInputChannel
Класс UdpInputChannel
реализует IInputChannel
. Он состоит из очереди входящих сообщений, которая заполняется сокетом прослушивателя UdpChannelListener
. Эти сообщения удаляются методом IInputChannel.Receive
.
Добавление элемента привязки
После создания фабрики и каналы нужно предоставить среде выполнения ServiceModel через привязку. Привязка - это коллекция элементов привязки, представляющая стек связи для адреса службы. Каждый элемент в стеке представлен элементом <привязки> .
В этом примере в качестве элемента привязки выступает элемент UdpTransportBindingElement
, являющийся производным элемента TransportBindingElement. Он переопределяет следующие методы создания фабрик, связанных с привязкой.
public IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
{
return (IChannelFactory<TChannel>)(object)new UdpChannelFactory(this, context);
}
public IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
{
return (IChannelListener<TChannel>)(object)new UdpChannelListener(this, context);
}
Он также содержит члены для клонирования элемента BindingElement
и возврата схемы (soap.udp).
Добавление поддержки метаданных для элемента привязки транспорта
Для интеграции в систему метаданных транспорт должен поддерживать как импорт, так и экспорт политики. Это позволяет создавать клиенты нашей привязки с помощью средства служебной программы метаданных ServiceModel (Svcutil.exe).
Добавление поддержки WSDL
За экспорт и импорт адресов в метаданных отвечает элемент привязки транспорта. При использовании привязки протокола SOAP элемент привязки транспорта должен также экспортировать в метаданных правильный URI (универсальный код ресурса) транспорта.
Экспорт WSDL
Для экспорта адресов элемент UdpTransportBindingElement
реализует интерфейс IWsdlExportExtension
. Метод ExportEndpoint
добавляет правильные сведения об адресации в порт WSDL.
if (context.WsdlPort != null)
{
AddAddressToWsdlPort(context.WsdlPort, context.Endpoint.Address, encodingBindingElement.MessageVersion.Addressing);
}
Реализация метода UdpTransportBindingElement
в элементе ExportEndpoint
также экспортирует URI транспорта, когда конечная точка использует привязку SOAP.
WsdlNS.SoapBinding soapBinding = GetSoapBinding(context, exporter);
if (soapBinding != null)
{
soapBinding.Transport = UdpPolicyStrings.UdpNamespace;
}
Импорт WSDL
Для расширения системы импорта WSDL для обработки импорта адресов нужно добавить в файл конфигурации средства Svcutil.exe следующую конфигурацию, как показано в файле Svcutil.exe.config.
<configuration>
<system.serviceModel>
<client>
<metadata>
<policyImporters>
<extension type=" Microsoft.ServiceModel.Samples.UdpBindingElementImporter, UdpTransport" />
</policyImporters>
</metadata>
</client>
</system.serviceModel>
</configuration>
При запуске Svcutil.exe существует два варианта обеспечить загрузку программой расширений импорта WSDL:
Наведите Svcutil.exe в файл конфигурации с помощью файла /SvcutilConfig:<file>.
добавить раздел конфигурации в файл Svcutil.exe.config, находящийся в том же каталоге, что и файл Svcutil.exe.
Тип UdpBindingElementImporter
реализует IWsdlImportExtension
интерфейс. Метод ImportEndpoint
импортирует адрес из порта WSDL.
BindingElementCollection bindingElements = context.Endpoint.Binding.CreateBindingElements();
TransportBindingElement transportBindingElement = bindingElements.Find<TransportBindingElement>();
if (transportBindingElement is UdpTransportBindingElement)
{
ImportAddress(context);
}
Добавление поддержки политик
Пользовательский элемент привязки может экспортировать утверждения политики в привязке WSDL для конечной точки службы, чтобы показать возможности этого элемента привязки.
Экспорт политики
Тип UdpTransportBindingElement
реализуется IPolicyExportExtension
для добавления поддержки экспорта политики. В результате класс System.ServiceModel.MetadataExporter
включает элемент UdpTransportBindingElement
при формировании политики для любой привязки, в которую он входит.
В методе IPolicyExportExtension.ExportPolicy
добавляется утверждение для UDP и еще одно утверждение, если используется режим многоадресной рассылки. Это связано с тем, что режим многоадресной рассылки влияет на построение стека связи и, следовательно, должен быть согласован обеими сторонами.
ICollection<XmlElement> bindingAssertions = context.GetBindingAssertions();
XmlDocument xmlDocument = new XmlDocument();
bindingAssertions.Add(xmlDocument.CreateElement(
UdpPolicyStrings.Prefix, UdpPolicyStrings.TransportAssertion, UdpPolicyStrings.UdpNamespace));
if (Multicast)
{
bindingAssertions.Add(xmlDocument.CreateElement(
UdpPolicyStrings.Prefix,
UdpPolicyStrings.MulticastAssertion,
UdpPolicyStrings.UdpNamespace));
}
Поскольку пользовательские элементы привязки транспорта отвечают за обработку адресов, реализация IPolicyExportExtension
в элементе UdpTransportBindingElement
должна также обрабатывать экспорт соответствующих утверждений политики WS-Addressing для указания используемой версии WS-Addressing.
AddWSAddressingAssertion(context, encodingBindingElement.MessageVersion.Addressing);
Импорт политики
Чтобы расширить систему импорта политик, нужно добавить в файл конфигурации Svcutil.exe следующую конфигурацию, как показано в файле Svcutil.exe.config.
<configuration>
<system.serviceModel>
<client>
<metadata>
<policyImporters>
<extension type=" Microsoft.ServiceModel.Samples.UdpBindingElementImporter, UdpTransport" />
</policyImporters>
</metadata>
</client>
</system.serviceModel>
</configuration>
Затем мы реализуем интерфейс IPolicyImporterExtension
из зарегистрированного нами класса (UdpBindingElementImporter
). В методе ImportPolicy()
нужно рассмотреть утверждения в нашем пространстве имен и обработать предназначенные для формирования транспорта и проверки, является ли он многоадресным. Кроме того, нужно удалить обрабатываемые утверждения из списка утверждений привязки. И опять при запуске Svcutil.exe существует два варианта интеграции:
Наведите Svcutil.exe в файл конфигурации с помощью файла /SvcutilConfig:<file>.
добавить раздел конфигурации в файл Svcutil.exe.config, находящийся в том же каталоге, что и файл Svcutil.exe.
Добавление стандартной привязки
Элемент привязки можно использовать двумя следующими способами.
С помощью пользовательской привязки: пользовательская привязка позволяет пользователю создать собственную привязку на основе произвольного набора элементов привязки.
С помощью предусмотренной в составе системы привязки, включающей наш элемент привязки. WCF предоставляет ряд системных привязок, таких как
BasicHttpBinding
,NetTcpBinding
иWsHttpBinding
. Каждая из них связана с четко определенным профилем.
В этом образце реализуется профиль привязки в SampleProfileUdpBinding
, производном от Binding. Привязка SampleProfileUdpBinding
содержит до четырех элементов привязки: UdpTransportBindingElement
, TextMessageEncodingBindingElement CompositeDuplexBindingElement
и ReliableSessionBindingElement
.
public override BindingElementCollection CreateBindingElements()
{
BindingElementCollection bindingElements = new BindingElementCollection();
if (ReliableSessionEnabled)
{
bindingElements.Add(session);
bindingElements.Add(compositeDuplex);
}
bindingElements.Add(encoding);
bindingElements.Add(transport);
return bindingElements.Clone();
}
Добавление пользовательского импортера стандартной привязки
Svcutil.exe и тип WsdlImporter
по умолчанию распознают и импортируют определенные системой привязки. В противном случае привязка импортируется как экземпляр CustomBinding
. Чтобы Svcutil.exe и тип WsdlImporter
могли импортировать привязку SampleProfileUdpBinding
, тип UdpBindingElementImporter
также выступает в качестве пользовательского импортера стандартной привязки.
Пользовательский импортер стандартной привязки реализует метод ImportEndpoint
в интерфейсе IWsdlImportExtension
, чтобы проверить импортированный из метаданных экземпляр класса CustomBinding
и определить, мог ли он быть сформирован определенной стандартной привязкой.
if (context.Endpoint.Binding is CustomBinding)
{
Binding binding;
if (transportBindingElement is UdpTransportBindingElement)
{
//if TryCreate is true, the CustomBinding will be replace by a SampleProfileUdpBinding in the
//generated config file for better typed generation.
if (SampleProfileUdpBinding.TryCreate(bindingElements, out binding))
{
binding.Name = context.Endpoint.Binding.Name;
binding.Namespace = context.Endpoint.Binding.Namespace;
context.Endpoint.Binding = binding;
}
}
}
Как правило, реализация пользовательского импортера стандартной привязки предусматривает проверку свойств импортированных элементов привязки на предмет того, что изменены только свойства, которые могли быть заданы стандартной привязкой, а все остальные свойства имеют значения по умолчанию. Простейшая стратегия для реализации импортера стандартной привязки - создать экземпляр стандартной привязки, распространить на экземпляр стандартной привязки свойства из элементов привязки, поддерживаемые стандартной привязкой, и затем сравнить элементы привязки из стандартной привязки с импортированными элементами привязки.
Добавление поддержки конфигурации
Для предоставления транспорта через конфигурацию нужно реализовать два раздела конфигурации. Первый - элемент BindingElementExtensionElement
для UdpTransportBindingElement
. За счет этого реализации CustomBinding
могут ссылаться на наш элемент привязки. Второй - Configuration
для SampleProfileUdpBinding
.
Элемент привязки элемента Extension
Этот раздел UdpTransportElement
представляет BindingElementExtensionElement
UdpTransportBindingElement
собой доступ к системе конфигурации. С помощью нескольких простых переопределений в примере определяется имя раздела конфигурации, тип элемента привязки и способ создания элемента привязки. Затем можно зарегистрировать раздел расширения в файле конфигурации, как показано в следующем коде.
<configuration>
<system.serviceModel>
<extensions>
<bindingElementExtensions>
<add name="udpTransport" type="Microsoft.ServiceModel.Samples.UdpTransportElement, UdpTransport" />
</bindingElementExtensions>
</extensions>
</system.serviceModel>
</configuration>
На расширение можно ссылаться из пользовательских привязок, чтобы использовать в качестве транспорта протокол UDP.
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding configurationName="UdpCustomBinding">
<udpTransport/>
</binding>
</customBinding>
</bindings>
</system.serviceModel>
</configuration>
Раздел привязки
Этот раздел SampleProfileUdpBindingCollectionElement
представляет StandardBindingCollectionElement
SampleProfileUdpBinding
собой доступ к системе конфигурации. Основная часть реализации делегируется классу SampleProfileUdpBindingConfigurationElement
, наследуемому от класса StandardBindingElement
. Имеет SampleProfileUdpBindingConfigurationElement
свойства, соответствующие свойствам SampleProfileUdpBinding
и функциям для сопоставления из привязки ConfigurationElement
. Наконец, метод OnApplyConfiguration
в классе SampleProfileUdpBinding
переопределяется, как показано в следующем образце кода.
protected override void OnApplyConfiguration(string configurationName)
{
if (binding == null)
throw new ArgumentNullException("binding");
if (binding.GetType() != typeof(SampleProfileUdpBinding))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
"Invalid type for binding. Expected type: {0}. Type passed in: {1}.",
typeof(SampleProfileUdpBinding).AssemblyQualifiedName,
binding.GetType().AssemblyQualifiedName));
}
SampleProfileUdpBinding udpBinding = (SampleProfileUdpBinding)binding;
udpBinding.OrderedSession = this.OrderedSession;
udpBinding.ReliableSessionEnabled = this.ReliableSessionEnabled;
udpBinding.SessionInactivityTimeout = this.SessionInactivityTimeout;
if (this.ClientBaseAddress != null)
udpBinding.ClientBaseAddress = ClientBaseAddress;
}
Для регистрации этого обработчика в системе конфигурации в соответствующий файл конфигурации добавляется следующий раздел.
<configuration>
<configSections>
<sectionGroup name="system.serviceModel">
<sectionGroup name="bindings">
<section name="sampleProfileUdpBinding" type="Microsoft.ServiceModel.Samples.SampleProfileUdpBindingCollectionElement, UdpTransport" />
</sectionGroup>
</sectionGroup>
</configSections>
</configuration>
После этого на него можно сослаться из раздела конфигурации serviceModel.
<configuration>
<system.serviceModel>
<client>
<endpoint configurationName="calculator"
address="soap.udp://localhost:8001/"
bindingConfiguration="CalculatorServer"
binding="sampleProfileUdpBinding"
contract= "Microsoft.ServiceModel.Samples.ICalculatorContract">
</endpoint>
</client>
</system.serviceModel>
</configuration>
Тестовые служба и клиент UDP
Тестовый код для использования этого примера транспорта находится в каталогах UdpTestService и UdpTestClient. Код службы состоит из двух тестов. Один из них настраивает привязки и конечные точки из кода, а другой - через конфигурацию. Оба теста используют две конечных точки. Одна конечная точка использует SampleUdpProfileBinding
значение reliableSession><true
. Другая конечная точка использует пользовательскую привязку с классом UdpTransportBindingElement
. Это эквивалентно использованию SampleUdpProfileBinding
с параметром reliableSession>false
.< Оба теста создают службу, добавляют для каждой привязки конечную точку, открывают службу и ожидают нажатия пользователем клавиши ВВОД перед тем, как закрыть службу.
При запуске приложения тестирования службы появится результат следующего вида.
Testing Udp From Code.
Service is started from code...
Press <ENTER> to terminate the service and start service from config...
Затем можно выполнить приложение тестирования клиента относительно опубликованных конечных точек. Приложение тестирования клиента создает клиент для каждой конечной точки и отправляет им по пять сообщений. Клиент получает следующий результат.
Testing Udp From Imported Files Generated By SvcUtil.
0
3
6
9
12
Press <ENTER> to complete test.
Полные результаты службы таковы.
Service is started from code...
Press <ENTER> to terminate the service and start service from config...
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
adding 0 + 0
adding 1 + 2
adding 2 + 4
adding 3 + 6
adding 4 + 8
Для выполнения клиентского приложения относительно конечных точек, опубликованных с помощью конфигурации, нажмите в службе клавишу ВВОД и снова запустите тестовый клиент. Служба должна предоставить следующие результаты.
Testing Udp From Config.
Service is started from config...
Press <ENTER> to terminate the service and exit...
Повторное выполнение клиента дает такие же результаты.
Для восстановления кода клиента и конфигурации с помощью Svcutil.exe запустите приложение службы и выполните следующий файл Svcutil.exe из корневого каталога образца.
svcutil http://localhost:8000/udpsample/ /reference:UdpTransport\bin\UdpTransport.dll /svcutilConfig:svcutil.exe.config
Обратите внимание, что Svcutil.exe не создает конфигурацию расширения привязки для SampleProfileUdpBinding
, поэтому ее нужно добавить вручную.
<configuration>
<system.serviceModel>
<extensions>
<!-- This was added manually because svcutil.exe does not add this extension to the file -->
<bindingExtensions>
<add name="sampleProfileUdpBinding" type="Microsoft.ServiceModel.Samples.SampleProfileUdpBindingCollectionElement, UdpTransport" />
</bindingExtensions>
</extensions>
</system.serviceModel>
</configuration>
Настройка, сборка и выполнение образца
Чтобы создать решение, следуйте инструкциям по созданию примеров Windows Communication Foundation.
Чтобы запустить пример в конфигурации с одним или несколькими компьютерами, следуйте инструкциям в разделе "Примеры Windows Communication Foundation".
См. раздел "Тестовые служба и клиент UDP" выше.