Elispprocess-send-string выдает неожиданную ошибку «процесс не запущен: прослушайте»

Я пытаюсь создать простой сетевой RPC-сервер/клиент в emacs lisp.
На данный момент у меня есть следующий (несколько минималистичный) код:

(defun handle-connection (proc msg)
  (message (format "connection received payload: %s" msg))
  (process-send-string proc "hello, nice to meet you"))

(defun handle-filter (proc msg)
  (message (format "got %s from %s" msg proc)))

(defun handle-filter-surfer (proc msg)
  (message (format "got %s from %s" msg proc)))

(defun server-sentinel (proc msg)
  (cond ((string-match "^open" msg) (handle-connection proc msg))
    (t (message "something went wrong"))))

(setq surfer (make-network-process :name "surfer" :server 5 :host 'local
                   :buffer "surfer" :filter 'handle-filter-surfer
                   :service 1337 :sentinel 'server-sentinel))

(setq client (make-network-process :name "client" :buffer "client"
                   :remote [127 0 0 1 1337]))

Кажется, все эти вызовы работают нормально.
Моя проблема в следующем: теперь я хочу отправить сообщение от клиента на сервер. В документации только сказано, что для отправки данных в процесс следует использовать process-send-string. Поэтому, естественно, я попытался (process-send-string surfer "asdf"), в результате чего:

Debugger entered--Lisp error: (error "Process surfer not running: listen")
  process-send-string(#<process surfer> "asdf")
  eval((process-send-string surfer "asdf") nil)

Я делаю это неправильно? Как отправить сообщение от подключенного клиента на сервер? При подключении клиента к серверу вызывается handle-connection, и в буфере клиента появляется строка «привет», поэтому, похоже, работает наоборот. Я думаю, мне нужно подключение, чтобы это работало, но как мне сказать emacs, что он должен использовать подключенный клиент для отправки сообщения серверному процессу?

Как создать страницу входа в систему с помощью HTML с использованием CSS
Как создать страницу входа в систему с помощью HTML с использованием CSS
Создание страницы входа в систему является важной частью создания веб-сайта или приложения, требующего аутентификации пользователя. Простую страницу...
1
0
57
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
(process-send-string client "asdf")
;; => got asdf from surfer <127.0.0.1:1337>

Насколько я понимаю, «клиент» действует как сокет, который позволяет вам взаимодействовать с сервером.

handle-filter, кстати, не используется.


Обновлено:

Вот некоторые ключевые моменты о сетевой связи Emacs (согласно справочному руководству Elisp):

  • Клиент — это не процесс, а скорее «соединение». Вы не можете убить его или послать ему сигналы. Функция delete-process закрывает соединение (по сути, это похоже на сокет).
  • Сервер — это процесс, но вы не можете общаться с ним напрямую. Когда он получает запрос на соединение, он создает новое сетевое соединение, представляющее только что установленное соединение.
  • Сам сервер не использует фильтры и датчики; они наследуются новым соединением, устанавливаемым при подключении клиента к серверу.
  • В отличие от обычных сокетов, объект соединения можно использовать для отправки строки (через process-send-string), но не для ее получения. Вместо этого входная строка отправляется в фильтр; фильтр по умолчанию отправляет его в указанный буфер или отбрасывает, если такой буфер не был указан (или :buffer nil был передан в make-network-process).

Для простоты в прилагаемом коде предполагается только один клиент и один сервер.

(defconst net-port        35678)
(defconst max-connections 1)

(defvar my-surfer         nil) ;; the listening server process
(defvar my-client->server nil) ;; a connection
(defvar my-server->client nil) ;; another connection

;;;; Server-side functions

(defun handle-connection (proc _)
  (message (format " -> handle-connection"))
  (setq my-server->client proc)) ;; set this so 'test-main' can continue

;; Messages from the client are passed here
(defun surfer-filter (proc msg)
  (message "[surfer-filter] %S received %S" proc msg))

(defun surfer-sentinel (proc msg)
  ;; (message "[surfer sentinel] proc %S  msg %s" proc msg)
  (cond ((string-prefix-p "open" msg)
         (handle-connection proc msg))
        ((string-prefix-p "deleted" msg)
         (message "-> server connection deleted"))
        (t (message "something went wrong"))))

;;;; Client-side

;; Messages from the server are sent here
(defun client-filter (_ msg)
  (message "[client-filter] received %S" msg))

;;;;

(defmacro my-delete-process(var-name)
  `(when ,var-name
     (delete-process ,var-name)
     (setq ,var-name nil)))

(defun test-main()
  (interactive)

  (with-current-buffer "*Messages*"
    (let ((inhibit-read-only t))
      (erase-buffer)))

  ;; Clean-up after the previous run
  (my-delete-process my-client->server)
  (my-delete-process my-surfer)
  (my-delete-process my-server->client)

  ;; Messages from the client are passed to 'surfer-filter'.
  ;; Since we have a filter, we can manage without a buffer.
  (setq my-surfer (make-network-process
                   :name "surfer" :server max-connections
                   :host 'local
                   ;; :buffer "surfer"
                   :filter 'surfer-filter
                   :service net-port :sentinel 'surfer-sentinel))

  ;; Messages from the server are passed to 'client-filter'
  (setq my-client->server
        (make-network-process
         :name "client" ;; :buffer "client"
         :filter 'client-filter
         :remote (vector 127 0 0 1 net-port)))

  (message "waiting for server connection...")
  (let ((i 0))
    ;; Wait for 2 seconds max
    (while (and (< i 20)
                (not my-server->client))
      (cl-incf i)
      (sleep-for 0.1)))
  (cl-assert my-server->client)

  (process-send-string my-client->server
                       "a message from the client")
  (process-send-string my-server->client
                       "a message from the server"))

Возможный результат:

waiting for server connection...
 -> handle-connection
[client-filter] received "a message from the server"
[surfer-filter] #<process surfer <127.0.0.1:45054>> received "a message from the client"

Я забыл добавить строку (set-process-filter client 'handle-filter). Ваше предложение работает, но у меня возник вопрос, как отправить данные с клиента на сервер. Поскольку одним из моих вопросов также был: «Я делаю что-то не так», я склонен принять ответ, потому что теперь я представляю, что Emacs всегда работает только как серверный процесс в таком сценарии. Затем клиент подключится к экземпляру Emacs. Думаю ли я сейчас в правильном направлении?

L0ren2 14.07.2024 17:11

Emacs может работать как клиент и сервер одновременно. Сервер работает в подпроцессе. Подробности выложу чуть позже.

BadEnglish 16.07.2024 12:16

Большое спасибо. Пример кода действительно помог. Я написал сценарий C++ для подключения к серверу elisp, работающему в emacs, и это тоже сработало :)

L0ren2 16.07.2024 19:01

Я рад, что смог помочь ;)

BadEnglish 16.07.2024 19:57

Другие вопросы по теме