Простой кроссплатформенный процесс для обработки коммуникации в Mono? - PullRequest
11 голосов
/ 20 марта 2011

Я работаю над приложением Mono, которое будет работать на Linux, Mac и Windows, и мне нужна возможность приложений (под одной ОС) отправлять простые строковые сообщения друг другу.

В частности, я хочу приложение для одного экземпляра.Если попытаться запустить второй экземпляр, он вместо этого отправит сообщение одному уже запущенному экземпляру.

DBus отсутствует, так как я не хочу, чтобы это было дополнительным требованием.Связь через сокет кажется сложной, так как окна, похоже, не разрешают подключение.Файлы с отображением в памяти не поддерживаются в Mono.Именованные каналы не поддерживаются в Mono.Кажется, что IPC не поддерживается в Mono.

Итак, существует ли простой способ отправки строковых сообщений на одном компьютере в серверное приложение, которое работает на каждом компьютере, без необходимости в разрешениях или дополнительных зависимостях?

Ответы [ 4 ]

4 голосов
/ 20 марта 2011

На моем Ubuntu (10.10 mono версия: 2.6.7) я пытался использовать WCF для межпроцессного взаимодействия с BasicHttpBinding, NetTcpBinding и NetNamedPipeBinding.Первые 2 работали нормально, для NetNamedPipeBinding я получил ошибку:

Тип канала IDuplexSessionChannel не поддерживается

при вызове метода ChannelFactory.CreateChannel ().

Я также пытался использовать Remoting (это устаревшая технология с момента появления WCF) с IpcChannel;Пример из этой msdn page запустился и работал без проблем на моей машине.

Я полагаю, у вас не должно возникнуть проблем с использованием WCF или Remoting в Windows, хотя не уверен насчет Mac, нонет никого из тех, кто рядом, чтобы проверить.Дайте мне знать, если вам нужны примеры кода.

надеюсь, это поможет, с уважением

3 голосов
/ 04 июля 2014

Я писал об этом в списке рассылки mono-dev.Было рассмотрено несколько систем межпроцессного обмена сообщениями общего назначения, в том числе DBus, класс System.Threading.Mutex, WCF, Remoting, именованные каналы ... В основном выводы mono не поддерживают класс Mutex (работаетдля межпоточных, а не для межпроцессных) и нет ничего доступного для платформы .

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

  • Откройте или создайте файл в известном месте с эксклюзивной блокировкой.(FileShare.None).Каждое приложение пытается открыть файл, выполнить свою работу и закрыть файл.Если не удается открыть, Thread.Sleep (1) и попробуйте снова.Это своего рода гетто, но оно работает кроссплатформенно, чтобы обеспечить межпроцессный мьютекс.
  • Сокеты.Первое приложение прослушивает localhost, какой-нибудь порт с высоким номером.Второе приложение пытается прослушать этот порт, но не открывается (потому что он уже есть у другого процесса), поэтому второй процесс отправляет сообщение первому процессу, который уже прослушивает этот порт.
  • Если у вас есть доступк транзакционной базе данных или системе передачи сообщений (sqs, rabbitmq и т. д.), используйте ее.
  • Конечно, вы можете определить, на какой платформе вы работаете, и затем использовать все, что работает на этой платформе.
1 голос
/ 20 марта 2011

Решил мою проблему двумя способами: именованным мьютексом (чтобы приложение могло запускаться на одной машине разными пользователями) и наблюдателем в файле сообщений.Файл открыт и записан для связи.Вот базовое решение, написанное на 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)
1 голос
/ 20 марта 2011

По вашей простой причине необходимости 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;
    }

Просто переберите список и найдите свое собственное ProcessName.

Чтобы отправить сообщение в ваше приложение, просто используйте MyProcess.StandardInput для записи в стандартный ввод приложения. Это работает только при условии, что ваше приложение является приложением с графическим интерфейсом.

Если у вас есть проблемы с этим, то вы можете использовать специальный файл блокировки. Используя класс FileSystemWatcher, вы можете проверить, когда он изменяется. Таким образом, второй экземпляр может записать сообщение в файл, а затем первый экземпляр заметит, что он изменяется, и может прочитать содержимое файла, чтобы получить сообщение.

...