(NET) NET (2003 год)

Remoting-программирование

Программирование в сетях можно вести в нескольких пространствах имен - System.NET.Sokets, System.Messaging, System.Runtime.Remoting. На этой страничке я расскажу о программировании в последнем пространстве - ибо при написании первой проги - я cтолкнулся с таким количеством глюков, что понял что в следующей своей проге (или кому-то другому) лучше сразу начинать с работающего проекта.

В Remoting некий класс можно сделать доступным через сеть. Для начала надо описать интерфейсы этого класса:

00001: Public Interface IRemoteObject
00002:     Function GetSum(ByVal X As Double) As Double
00003:     Function GetLocation() As String
00004: End Interface

Для чего это надо делать. Дело в том, что в классической технологии Remoting надо копию этого серверного класса отдавать клиенту и устанавливать на него ссылку. Как я не старался - после установления ссылки это серверный класс просто прилинковывался статически и никакого удаленного вызова просто не происходило. Поэтому на клиенте я прилинковываю ТОЛЬКО интерфейс этого серверного класса - физическое отсутствие на клиенте самого класса гарантирует от ошибки когда никакого удаленного вызова нет и в помине.

Теперь собственно сам класс, который можно будет вызывать через сеть. Он в технологии Remoting является серверным классом (хотя как раз-то расположен он обычно на клиенте в классическом понимании этого слова) - этот класс только выполняет требования клиента и никогда не создает действий по своей инициативе. Хотя иногда может - когда он генерит события - но это более сложный вариант...

Для простейшего проекта текст этого класса-исполнителя будет таким:

00001: Public Class RemoteObject
00002:     Inherits MarshalByRefObject
00003:     Implements RemoteObjectInterfaces.IRemoteObject
00004: 
00005:     Public Function Calc(ByVal X As Double) As Double _
00006:     Implements RemoteObjectInterfaces.IRemoteObject.GetSum
00007:         Calc = X * X
00008:         Console.WriteLine("Получено - " & X.ToString)
00009:     End Function
00010: 
00011:     ' This method allows you to verify that Remoting is working.
00012:     Public Function GetLocation() As String _
00013:     Implements RemoteObjectInterfaces.IRemoteObject.GetLocation
00014:         Return AppDomain.CurrentDomain.FriendlyName
00015:     End Function
00016: 
00017: End Class

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

Также обратите внимание на строку 14 - эта замечательная находка (не моя) позволяет определить на какой именно машине этот класс сейчас исполняется. У клиента должно получатся имя приложения, выполняемого на сервере.

Следующая фишка технологии Remoting - этот класс (доступный удаленно ) должен где-то хостится, т.е. на неком аналоге Web-сервера, иначе говоря нужен класс поддерживающий соединение с сетью и загружающий при вызовах экземпляр вышеописанного класса. Этот класс делают часто в виде службы. Он должен висеть на указанном порту и слушать сеть. Если никто сеть не слушает - то никакого взаимодействия по Remoting не будет. Для простейшего варианта этот класс может быть таким:

00001: Imports System.Runtime.Remoting
00002: 
00003: Module Module1
00004: 
00005:     Dim Channels() As System.Runtime.Remoting.Channels.IChannel
00006:     Dim Channel As Object
00007:     Dim Config As System.Runtime.Remoting.WellKnownServiceTypeEntry
00008: 
00009:     Sub Main()
00010:         Try
00011:             RemotingConfiguration.Configure("..\App1.config")
00012:         Catch x As SystemException
00013:             MsgBox("Ошибка загрузки конфигурации сервера .Remoting " & vbCrLf & x.Message)
00014:         End Try
00015: 
00016:         Console.WriteLine("Сервер NET.REMOTING Started at        : " & Now & vbCrLf)
00017:         Config = RemotingConfiguration.GetRegisteredWellKnownServiceTypes(0)
00018:         Channels = System.Runtime.Remoting.Channels.ChannelServices.RegisteredChannels
00019:         For Each Channel In Channels
00020:             Console.WriteLine("Канал (Channel) : " & Channel.channeldata.channeluris(0) & vbCrLf)
00021:         Next
00022:         Console.WriteLine(vbCrLf & _
00023:         "Имя REMOTING-сервиса     - ObjectUri  : " & Config.ObjectUri & vbCrLf & _
00024:         "Режим (SingleTon/SingleCall)    Mode  : " & Config.Mode & vbCrLf & _
00025:         "Удаленно доступный класс - ObjectType : " & Config.ObjectType.FullName.ToString & vbCrLf & _
00026:         "Удаленно будет вызвана сборка         : " & Config.ObjectType.Assembly.Location & vbCrLf)
00027: 
00028:         Console.WriteLine("Enter - Закрыть сервер ...")
00029:         Console.ReadLine()
00030:     End Sub
00031: 
00032: End Module

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




В принципе есть полное описание всех тегов конфигурации Remoting - которое можно посмотреть здесь. В этом файле важно правильно задать имена классов и сборки в параметре Type и имя Remoring-сервиса в параметре objectUri. Mode - это срок жизни серверного класса - которое определяет наш класс-хостер. Такое как указано выше - озачает загрузку классом-хостером каждого экземпляра серверного класса на каждый запрос. Sigleton - означает загрузку одного класса для всех клиентских запросов. RemoteObjects - означает здесь имя сборки (DLL-файла), RemoteObject - имя серверного класса в этой сборке.

Следующий этап - это изготовление клиента, который будет отсылать серверу запросы. Допустим это будет вот такая форма и вот такой текст:

00001: Imports System.Runtime.Remoting
00002: Imports System.Runtime.Remoting.Lifetime
00003: 
00004: Public Class ClientForm
00005:     Inherits System.Windows.Forms.Form
00006: 
00007: #Region " Windows Form Designer generated code "
00008: #End Region
00009: 
00010:     Private RemoteObj As RemoteObjectInterfaces.IRemoteObject
00011: 
00012:     Private Sub Form_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
00013: 
00014:         Try
00015:             ' Configure the network channel.
00016:             RemotingConfiguration.Configure("Client.exe.config")
00017:         Catch x As System.Exception
00018:             MsgBox("Не загружена клиентская конфигурация Remoting." & vbCrLf & x.Message)
00019:         End Try
00020: 
00021: 
00022:         ' Register the object using the interface and a URL defined
00023:         ' in the <appSettings> section of the configuration file.
00024:         Dim Obj As Object
00025:         Obj = Activator.GetObject( _
00026:         GetType(RemoteObjectInterfaces.IRemoteObject), _
00027:         System.Configuration.ConfigurationSettings.AppSettings("RemoteObjUrl"))
00028: 
00029:         RemoteObj = CType(Obj, RemoteObjectInterfaces.IRemoteObject)
00030:         
00031:         Try
00032:             ' Access the remote object through the interface.
00033:             lblInfo.Text &= vbNewLine & "Object executing in: " & RemoteObj.GetLocation
00034:         Catch x As System.Exception
00035:             MsgBox("Нет связи с сервером." & vbCrLf & x.Message)
00036:         End Try
00037:     End Sub
00038: 
00039:     Private Sub cmdTest_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdTest.Click
00040:         Try
00041:             'Вызов метода удаленного обьекта с параметром
00042:             TextBox1.Text = RemoteObj.GetSum(TextBox1.Text)
00043:         Catch x As System.Exception
00044:             MsgBox("Нет связи с сервером." & vbCrLf & x.Message)
00045:         End Try
00046:     End Sub
00047: End Class

Основная фишка этого текста - активация серверного класса не по NEW (хотя именно так положено по правилам) - а используя его описание интерфейсов - на которые ставится ссылка при компиляции - строки 24-29. Второй момент - загрузка конфигурации извне, причем описание сервиса по идее должно было бы выглядеть вот так:



на самом деле для нашей версии выглядит вот так:



Естественно и конфигурация могла бы обрабатыватся проще (если бы мы сделали доступным клиенту не только описание интерфейсов серверного класса, а весь класс:

00001:        RemotingConfiguration.Configure("Client.exe.config")
00002:        Dim RemoteObj As New RemoteObjects.RemoteObject()
и соответственно в конфигурации можно было бы прямо указывать WELLKNOWN, а не просто дополнительный ключ. В том, что конфигурация клиента из дополнительного ключа загружена правильно мы можем убедится - посмотрев на нее в отладчике.


Когда сервер REMOTING запущен:

то открытый порт мы можем увидеть любым сканером. Теперь только остается запустить клиента на другой машине и наслаждатся прохождением пакетов через сеть. В этом проекте был использован бинарный упаковщик, а он может быть и SOAP (как в Web-службах) или даже написан самолично. Но это более тонкие вещи, чем рассмотренные на этой страничке.

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

Comments ( )
<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21>  <22>  <23
Link to this page: //www.vb-net.com/dotnet/tour15/index.htm
<SITEMAP>  <MVC>  <ASP>  <NET>  <DATA>  <KIOSK>  <FLEX>  <SQL>  <NOTES>  <LINUX>  <MONO>  <FREEWARE>  <DOCS>  <ENG>  <CHAT ME>  <ABOUT ME>  < THANKS ME>