Простой кросс-платформенный процесс для обработки связи в 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)