Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Легкой Inter-Process Communication на C#

Anna | 18.06.2014 | нет комментариев
В начале работы junior разработчиком мне пришлось столкнуться с таким малопонятным для меня на то время представлением, как Inter-Process Communication. Это была полная дикость для начинающего программиста, тот, что и в рамках логики одного приложения ориентировался то с огромным трудом. Стоит упомянуть, что план написан на Delphi, а сам механизм IPC реализован с поддержкой File Mapping и Windows Messages.
Что ошеломительно, узнал я том, как каждая эта система работает изнутри, через едва ли не год, когда пришлось немного с ней повозиться. И только тогда я окончательно понял, насколько высококлассной была её реализация, а API – комфортен. Кому увлекательна реализация чего-то схожего на вышеупомянутую систему под С# – умоляю под кат.

От того что в свободное время я постигаю .NET Framework, то меня заинтересовало, насколько легко/удобно реализовано IPC на .NET. К собственному разочарованию осознал, что функционал с коробки гораздо уступает в удобстве и простоте кустарной делфийской системе. Здесь дозволено развести отличный такой холивар, опираясь на то что .NET ориентирован на абстрагирование от канала передачи данных и разрешает идентично отлично шарить объекты как по сети, так и между процессами. Но от того что тема статьи – именно IPC, то попрошу этого не делать.Малое вступление. Я не смог до конца понять всех хитростей IPC на .NET, но, покурив мануалы ознакомившись с тематическими статьями, осознал, что реально применять следующие варианты:
1. COM,
2. File Mapping,
3. IPC Channels.
Так как реализация с применением COM либо File Mapping будет немного чем отличатся от аналогов на других языках, выбор однозначно пал на встроенный механизм IPC для .NET.

Позже попыток написать немного-мальски функциональное приложение понял, что даже передача легкой строки с его применением требует лишних телодвижений на обоих приложениях – как в отправителе, так и в приемнике. В результате, для шары объекта между процессами нужно сделать что-то как бы:

Сервер:

IpcChannel serverChannel = new IpcChannel("MyServerChannel");
ChannelServices.RegisterChannel(serverChannel);
RemotingConfiguration.RegisterWellKnownServiceType(
  typeof(IPCChannelRemoting.MyRemoteObject),
  "SharedObj",
  WellKnownObjectMode.SingleCall);

Заказчик:

IpcChannel clientChanel = new IpcChannel("myClient");
ChannelServices.RegisterChannel(clientChanel); 
ISharedObj obj = (Remoteable.ISharedAssemblyInterface)Activator.GetObject(
  typeof(Remoteable.ISharedAssemblyInterface),
  "ipc://MyServerChannel/SharedObj ");

Но что, если обмен данными должен применяться повсюду в приложении? В таком случае придется дублировать выше изложений код повсеместно и оговорить правила создания URI для shared объектов. А если нужно не легко запрашивать данные с иного процесса, но и подписываться на приобретение некоторого сигнала/сообщения? Дозволено сделать Thread/Timer тот, что лупит в цикле проверки либо применять WaitForSingleObject/EventWaitHandle. В всеобщем, здесь теснее не обойтись без собственноручно сделанной архитектуры.

По предыдущему навыку разработки приложения, которое обширно использует IPC механизмы, дюже комфортно применять дальнейший подход:
– есть три основных сущности: отправитель, получатель и сообщение;
– у всякого получателя и отправителя есть свои уникальные ID, на которые и идет отправка сообщений. Они могут быть привязаны к PID приложения, handle’y окна либо любому общеизвестному идентификатору, о котором вестимо обеим сторонам;
– сообщение – это абстрактное представление, которое может содержать в себе поля любого* типа, быть синхронным либо асинхронным. Приложения, которые обмениваются этими сообщениями, обязаны знать о определенных классах преемниках базовых сообщений. Различие между синхронными и асинхронными сообщениями в том, что в синхронное сообщение дозволено положить итог запроса, если это нужно, и он будет доступен отправителю сразу позже обработки сообщения (по возврату стека от вызова способа отправки).

В выводе, применяя получившуюся систему, отправление данных между процессами сводится к
– созданию объектов отправителя и сообщения,
– отправления сообщения с поддержкой отправителя,
– его обработки в процессе получателя.

using (BaseIPCDispatcher dispatcher = new BaseIPCDispatcher(slaveReceaverGUID)) {
  TestAsyncComplexMessage testMessage = new TestAsyncComplexMessage (ReceaverID, null);
  dispatcher.Dispatch(testMessage);
}

Подписка на приобретение сообщения в ином, ну либо том же процессе:

…
Receiver.OnReceaveIPCMessage  = OnReceaveMessage;
…
private void OnReceaveMessage(object sender, ReceaveMessageEventArgs e) {
  TestAsyncComplexMessage testAsyncMessage = e.Message as TestAsyncComplexMessage;
  if (testAsyncMessage != null) {
    // process message
  }
}

Имхо, получилось немножко больше видимо, эластично и читабельно. Код покрыт функциональными тестами с применением Master/Slave архитектуры.

Кто желает ознакомиться – итог лежит на GitHub
github.com/perevernihata/SimpleIPCCommSystem
З.Ы. Я понимаю, что, допустимо, я по незнанию изобрел свой велосипед с квадратными колесами, – но так чай это чертовски увлекательно делать! Конструктивная критика приветствуется.

* (Serializable для асинхронных сообщений).

 

Источник: programmingmaster.ru

 

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB