Працюючи над інженерними системами, які часто включають застарілі компоненти, я часто стикаюся з проблемами інтеграції застарілих елементів з сучасними платформами. Наприклад, можуть виникати ситуації, коли необхідно підтримувати застарілі формати файлів, які можуть бути відкриті лише 32-розрядним компонентом. Це обмеження ставить перед вибором: або залишатися на застарілій платформі, відмовившись від переваг сучасних фреймворків, таких як 64-розрядна адресація, або ізолювати логіку застарілого компонента в окремому процесі, з яким головна програма взаємодіє.
Є безліч сценаріїв для міжпроцесної комунікації (IPC) на тій самій машині, включаючи:
- Підтримка компонентів, побудованих для іншої платформи, ніж основна система.
- Запуск кількох паралельних незалежних процесів для подолання обмежень системи.
- Забезпечення обміну даними між кількома одночасно працюючими додатками.
- І багато інших.
Чому WitCom?
Протягом багатьох років я використовував WCF завдяки його гнучкості, зокрема підтримці вибору оптимізованих транспортів, таких як іменовані канали для локальних взаємодій. Однак після міграції на .NET Core WCF більше не був повністю доступний. Хоча останні версії .NET знову підтримують WCF, його поточний статус залишається невизначеним.
Одна з особливостей WCF, яка виділялася, це ServiceContract, що дозволяє визначити інтерфейс служби. Цей підхід спрощує розробку: клієнт, інтегруючи службу WCF, автоматично генерує необхідний обгортковий код, що усуває необхідність вгадувати імена функцій або параметри. На жаль, як SignalR, так і gRPC вимагають викликів методів за допомогою текстових імен методів, що ускладнює підтримку коду.
Зустрічайте WitCom
Кілька років тому я відкрив IpcServiceFramework, який використовує інтерфейси для визначення служб і використовує рефлексію для розпакування та виклику методів на стороні служби. Хоча проект обіцяв багато, він більше не підтримувався. Натхнений його основною концепцією, я розробив власну реалізацію, яка переросла в WitCom.
WitCom — це фреймворк для комунікації, схожий на WCF, розроблений для .NET. Він дозволяє розробникам визначати інтерфейси служб, вибирати транспорт і встановлювати повнодуплексну комунікацію з мінімальними зусиллями. Підтримувані транспорти включають поширені варіанти, такі як іменовані канали, TCP та WebSocket, а також унікальну підтримку для пам'яті, що відображається в файлах.
Це дозволяє здійснювати надшвидку комунікацію з низькою затримкою в повнодуплексному режимі на локальній машині, що ідеально підходить для передачі великих обсягів даних з максимальною ефективністю.
Приклад: Міжпроцесна комунікація з WitCom
Приклад реалізації можна знайти в репозиторії WitCom на GitHub.
Крок 1: Визначення контракту служби
public interface IExampleService
{
event ExampleServiceEventHandler ProcessingStarted;
event ExampleServiceProgressEventHandler ProgressChanged;
event ExampleServiceProcessingEventHandler ProcessingCompleted;
bool StartProcessing();
void StopProcessing();
}
public delegate void ExampleServiceEventHandler();
public delegate void ExampleServiceProgressEventHandler(double progress);
public delegate void ExampleServiceProcessingEventHandler(ProcessingStatus status);
WitCom підтримує повнодуплексну комунікацію нативно, використовуючи зворотні виклики подій, і підтримує будь-який тип делегата (наприклад, PropertyChangedEventHandler
).
Крок 2: Реалізація служби в агенті
Процес агента хостить службу:
public class ExampleService : IExampleService
{
public event ExampleServiceEventHandler ProcessingStarted = delegate { };
public event ExampleServiceProgressEventHandler ProgressChanged = delegate { };
public event ExampleServiceProcessingEventHandler ProcessingCompleted = delegate { };
private CancellationTokenSource? CancellationTokenSource { get; set; }
public bool StartProcessing()
{
if (CancellationTokenSource != null) return false;
CancellationTokenSource = new CancellationTokenSource();
Task.Run(Process);
ProcessingStarted();
return true;
}
public void StopProcessing()
{
CancellationTokenSource?.Cancel();
}
private void Process()
{
ProcessingStatus status = ProcessingStatus.Success;
for (int i = 1; i <= 100; i++)
{
if (CancellationTokenSource?.IsCancellationRequested == true)
{
status = ProcessingStatus.Interrupted;
break;
}
ProgressChanged(i);
Thread.Sleep(100);
}
ProcessingCompleted(status);
CancellationTokenSource = null;
}
}
Крок 3: Запуск процесу агента
Процес хоста запускає агента як окремий процес, передаючи адресу комунікації через аргументи командного рядка.
Наприклад:
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "Agent.exe",
Arguments = "--address=ExampleMemoryMap",
UseShellExecute = false,
}
};
process.Start();
Крок 4: Запуск сервера в агенті
Агент запускає сервер і слухає підключення за отриманою адресою:
var server = WitComServerBuilder.Build(options =>
{
options.WithService(new ExampleService());
options.WithMemoryMappedFile("ExampleMemoryMap");
options.WithEncryption();
options.WithJson();
options.WithAccessToken("SecureAccessToken");
options.WithTimeout(TimeSpan.FromSeconds(1));
});
server.StartWaitingForConnection();
Крок 5: Створення клієнта в хості
Процес хоста підключається до агента:
var client = WitComClientBuilder.Build(options =>
{
options.WithMemoryMappedFile("ExampleMemoryMap");
options.WithEncryption();
options.WithJson();
options.WithAccessToken("SecureAccessToken");
options.WithTimeout(TimeSpan.FromSeconds(1));
});
if (!await client.ConnectAsync(TimeSpan.FromSeconds(5), CancellationToken.None))
{
Console.WriteLine("Не вдалося підключитися.");
return;
}
var service = client.GetService();
service.ProcessingStarted += () => Console.WriteLine("Обробка розпочалась!");
service.ProgressChanged += progress => Console.WriteLine($"Прогрес: {progress}%");
service.ProcessingCompleted += status => Console.WriteLine($"Обробка завершена: {status}");
Основні переваги WitCom
- Контракти сервісів: Визначайте інтерфейси сервісів для чистого і підтримуваного API.
- Багато транспортів: Вибір між Named Pipes, TCP, WebSocket або пам'яттю-картованими файлами.
- Повнодуплексна комунікація: Події та зворотні виклики підтримуються нативно.
- Шифрування: Захищена комунікація з шифруванням на основі AES/RSA.
- Авторизація: Аутентифікація на основі токенів забезпечує підключення лише авторизованих клієнтів.
- Висока продуктивність: Оптимізуйте IPC для локальної машини з використанням пам'яті-картованих файлів.
- Просте оброблення помилок: Використовуйте
WitComExceptionFault
для обробки помилок комунікації.
Висновок
WitCom — це потужна та сучасна альтернатива для міжпроцесної комунікації в .NET, яка поєднує найкращі функції WCF з сучасними варіантами транспорту. Для отримання додаткової інформації відвідайте документацію WitCom і ознайомтесь з прикладами на GitHub.
Перекладено з: Inter-process Communication with WitCom