Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Emacs Lisp network connections - what to do with the process object?

Suppose there is a TCP server up and running on localhost:8080, in another Lisp dialect that understands lists. Now I open a network connection in Elisp

setq pserv (open-network-stream plisp "test1.l" "localhost" 8080)

and successfully assign an open network process object to variable pserv. But then, whats next, how do I use this process object to send requests to the server? What I want to do is to send lists to the other server (code as data) that are evaluated and the results returned.

In the above statement, "test1.l" is the Emacs buffer associated with the process, so the results should be printed in that buffer. What if I put nil there and the process is not associated with any buffer - how do I access the server results (possibly in list form too) from Elisp or from the process object?

The Elisp manual seems to take that knowledge for granted, but I'm a bit lost here. Every hints would be appreciated.

like image 266
Thorsten Avatar asked Jun 04 '11 20:06

Thorsten


1 Answers

Client/server communication is handled via asynchronous processes. That means that unfortunately, you don't have a function "send" that you pass your data to be sent to the server and that returns to you the server's reply. The reason for that is that network communication can be slow and that would block all other operations within Emacs which is a single-threaded program.

To send data to your server, use (process-send-string process string). The first parameter is your network connection, which Emacs treats like asynchronous processes. Since you have that subprocess-object already stored in the variable pserv, you could write:

(process-send-string pserv "(my data (can be (in) (list) form))")

to send a string to the server.

To read the server's reply, you use a process filter function, which are callbacks that get invoked with whatever the server sends back to you. So you first have to define such a callback function, say:

(defun handle-server-reply (process content)
   "Gets invoked whenever the server sends data to the client."
   ...)

This function takes two arguments, the network process and the content data that the server sends. There's one tricky point to this though: the server reply may be split up into sub-contents. That is, when handle-server-reply gets called, the content argument may only contain parts of the server reply. It may get called again later with further content. So make sure you handle that correctly.

To declare your function as a callback, use:

(set-process-filter pserv 'handle-server-reply)

As always, character encoding can be a pita, so look into the following two functions and decide whether you might need them:

(set-process-filter-multibyte pserv t)
(set-process-coding-system pserv 'utf-8 'utf-8)

Make sure to set these before assigning a process filter function.

You might also be interested in surveying the status of your network connection, for instance, to handle cases where the connection gets closed unexpectedly. For that you can use so-called sentinel functions, another type of callback through which you get informed about changes of the process status:

(set-process-sentinel pserv 'sentinel-function)

(defun sentinel-function (process event)
  "Gets called when the status of the network connection changes."
   ...)

The event parameter contains the information about the way in which the connection status changed.

I think the Emacs process documentation has been pointed out before. It's definitely worth reading.

like image 78
Thomas Avatar answered Sep 28 '22 22:09

Thomas