make-network-process
支持 TCP/UDP/Unix Domain Socket,我们在用 url.el、LSP 和 Emacs Server 底层可能都会用到这个函数,我给它写了 4 个例子,每一个协议一个例子,最后一个例子是关于 Server 的,而不是 Client。
HTTP 客户端 (TCP)
(let ((proc (make-network-process
:name "http-client"
:buffer "*http-client*"
:host "example.com"
:service 80)))
(process-send-string
proc
(concat
"GET / HTTP/1.1\r\n"
"Host: example.com\r\n"
"Connection: close\r\n"
"\r\n"))
(display-buffer (process-buffer proc)))
:host
写域名或者 IP 地址,比如 example.com 或者 93.184.216.34。:service
填端口号或者协议名称,比如数字 80 或者字符串 http。
DNS 客户端 (UDP)
向 114.114.114.114 询问 example.com 的 IP 地址
(let ((proc (make-network-process
:name "dns-client"
:buffer "*dns-client*"
:host "114.114.114.114"
:service 53
:type 'datagram
:coding 'binary)))
(process-send-string
proc
(unibyte-string
0 0 1 0
0 1 0 0
0 0 0 0
7 ?e ?x ?a ?m ?p ?l ?e
3 ?c ?o ?m
0
0 1 0 1))
(accept-process-output proc 3)
(require 'bindat)
(bindat-unpack
'((ip ip))
(with-current-buffer (process-buffer proc)
(set-buffer-multibyte nil)
(substring (buffer-string) -4))))
;; => ((ip . [93 184 216 34]))
:type 'datagram
表示用 UDP,不然默认用 TCP。:coding 'binary
表示不编码数据。
Emacs Server 客户端 (Unix Domain Socket)
使用 Emacs Server 计算 (+ 1 2)
(let ((proc (make-network-process
:name "emacsclient"
:buffer "*emacsclient*"
:family 'local
:service (expand-file-name
server-name
server-socket-dir))))
(process-send-string
proc
(concat "-eval "
(server-quote-arg (format "%S" '(+ 1 2)))
"\n"))
(accept-process-output proc)
(display-buffer (process-buffer proc)))
:family 'local
表示用 Unix Domain Socket,不然默认用 IP v4/6。:service
不再是 TCP/UDP 端口了,而是 Socket 文件的路径。
HTTP 服务器
报告时间的 HTTP 服务器:
~ $ curl localhost:8000
Wed Dec 18 23:45:18 2019
(make-network-process
:name "http-server"
:server t
:service 8000
:sentinel
(lambda (process event)
(cond
((string-prefix-p "open from" event)
(process-send-string process
(concat "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 24\r\n"
"\r\n"
(current-time-string))))
((string= "connection broken by remote peer\n" event)
(kill-buffer (process-buffer process))))))
:server t
表示 Server,不然默认是 Client。服务器每次接收连接时都会创建一个新的 Process,专门处理这个连接。