Простой кросс-платформенный процесс для обработки связи в Mono?
Я работаю над Mono-приложением, которое будет работать на Linux, Mac и Windows, а также нужно, чтобы приложения (на одном os) отправляли простые строковые сообщения друг другу.
В частности, я хочу приложение с одним экземпляром. Если второй экземпляр будет запущен, он отправит сообщение только одному запущенному экземпляру.
DBus отсутствует, так как я не хочу, чтобы это было дополнительным требованием.
Связь сокета кажется сложной, поскольку окна, похоже, не позволяют разрешать подключение.
Файлы с отображением памяти, похоже, не поддерживаются в Mono.
Именованные каналы не поддерживаются в Mono.
IPC, похоже, не поддерживается в Mono.
Итак, существует ли простой способ отправки строковых сообщений на одной машине серверному приложению, которое работает на всех os, без необходимости разрешений или дополнительных зависимостей?
Ответы
Ответ 1
Я написал об этом в списке рассылки mono-dev. Были рассмотрены несколько систем обмена сообщениями общего назначения, в том числе DBus, System.Threading.Mutex, WCF, Remoting, Named Pipes... Выводы были в основном mono не поддерживает класс Mutex (работает для межпоточных, а не для межпроцессного процесса) и нет доступной агностики для платформы.
Я только мог представить три возможных решения. У всех есть свои недостатки. Может быть, есть лучшее решение, или, может быть, просто лучшие решения для определенных целей, или, возможно, есть некоторые межплатформенные сторонние библиотеки, которые вы могли бы включить в свое приложение (я не знаю). Но это лучшие решения, которые я имею удалось найти:
- Откройте или создайте файл в известном месте с исключительной блокировкой. (FileShare.None). Каждое приложение пытается открыть файл, выполнить его работу и закрыть файл. Если не удается открыть, Thread.Sleep(1) и повторите попытку. Это своего рода гетто, но он работает кросс-платформенным, чтобы обеспечить взаимную обработку мьютекса.
- Розетки. Первое приложение прослушивает локальный хост, некоторый порт с высоким номером. Второе приложение пытается прослушивать этот порт, не открывается (потому что какой-то другой процесс уже имеет его), поэтому второй процесс отправляет сообщение первому процессу, который уже прослушивает этот порт.
- Если у вас есть доступ к транзакционной базе данных, или система передачи сообщений (sqs, rabbitmq и т.д.), используйте ее.
- Конечно, вы можете определить, на какой платформе вы находитесь, а затем использовать все, что работает на этой платформе.
Ответ 2
На моем ubuntu (10.10 mono version: 2.6.7) Я пробовал использовать WCF для межпроцессного взаимодействия с BasicHttpBinding, NetTcpBinding и NetNamedPipeBinding. Первые 2 работали нормально, для NetNamedPipeBinding у меня получилась ошибка:
Тип канала IDuplexSessionChannel - не поддерживается
при вызове метода ChannelFactory.CreateChannel().
Я также пробовал использовать Remoting (которая является старой технологией после выхода WCF) с IpcChannel; пример из этой msdn page начался и работал без проблем на моей машине.
Я полагаю, что у вас не должно быть проблем с использованием WCF или Remoting на Windows, но не уверен в Mac, хотя у них нет ни одного из тех, кто тестирует. Дайте мне знать, если вам нужны примеры кода.
надеюсь, что это поможет, считает
Ответ 3
По вашей простой причине, требующей IPC, я бы поискал другое решение.
Этот код подтвержден для работы в Linux и Windows. Должен работать и на Mac:
public static IList Processes()
{
IList<Process> processes = new List<Process>();
foreach (System.Diagnostics.Process process in System.Diagnostics.Process.GetProcesses())
{
Process p = new Process();
p.Pid = process.Id;
p.Name = process.ProcessName;
processes.Add(p);
}
return processes;
}
Просто перейдите в список и найдите собственное имя процесса.
Чтобы отправить сообщение в ваше приложение, просто используйте MyProcess.StandardInput
для записи на стандартный ввод приложений. Это работает только при условии, что ваше приложение является графическим приложением.
Если у вас есть проблемы с этим, вы можете использовать специализированный файл "lock". Используя класс FileSystemWatcher, вы можете проверить, когда он изменится. Таким образом, второй экземпляр может записать сообщение в файл, а затем уведомление первого экземпляра, которое оно изменит и может прочитать в содержимом файла, чтобы получить сообщение.
Ответ 4
Решила мою проблему двумя способами: именованным мьютексом (чтобы приложение можно было запускать на одном компьютере разными пользователями) и наблюдателем в файле сообщений. Файл открывается и записывается для связи. Вот базовое решение, написанное в IronPython 2.6:
(mutex, locked) = System.Threading.Mutex(True, "MyApp/%s" % System.Environment.UserName, None)
if locked:
watcher = System.IO.FileSystemWatcher()
watcher.Path = path_to_user_dir
watcher.Filter = "messages"
watcher.NotifyFilter = System.IO.NotifyFilters.LastWrite
watcher.Changed += handleMessages
watcher.EnableRaisingEvents = True
else:
messages = os.path.join(path_to_user_dir, "messages")
fp = file(messages, "a")
fp.write(command)
fp.close()
sys.exit(0)