Closed nixz closed 11 years ago
Nix, be sure when instantiating tcp-server
to specify :stream t
if you want a stream to come through. As far as wrapping a character stream around a binary stream, I believe you can use flexi-streams
for this purpose. Here's a quick example:
(ql:quickload :cl-async)
(ql:quickload :flexi-streams)
(defpackage :char-stream
(:use :cl))
(in-package :char-stream)
(defun start-server ()
(let ((char-stream nil))
(as:tcp-server nil 8090
(lambda (sock stream)
(declare (ignore sock))
;; wrap the binary stream in a flexi-stream (if this hasn't happened already)
(unless char-stream
(setf char-stream (flexi-streams:make-flexi-stream stream :external-format :utf-8)))
;; now read from flexistream (which is set up by default as a character stream)
(let ((buf (make-array 1024 :element-type 'character)))
(loop for n = (read-sequence buf char-stream)
while (< 0 n) do
;; coerce the buffer we read to a string and print it out
(format t "GOT: ~s~%" (coerce (subseq buf 0 n) 'string)))))
(lambda (ev)
(format t "listener ev: ~a~%" ev))
:stream t)))
(defun start-client ()
(let* ((char-stream nil)
(stream (as:tcp-connect "127.0.0.1" 8090
(lambda (sock data)
(declare (ignore sock data)))
(lambda (ev)
(format t "client ev: ~a~%" ev))
:stream t)))
;; here we write a string to the flexi-stream, which converts it to binary before sending
(setf char-stream (flexi-streams:make-flexi-stream stream :external-format :utf-8))
(write-sequence "Hello!" char-stream)))
(as:start-event-loop
(lambda ()
(start-server)
(start-client))
:catch-app-errors t)
Once started, the server will receive the "Hello!" string. This gets converted to binary when it's sent by the client, and converted back to a sequence of characters once the server reads it through the flexi stream (converted to a string via coerce
).
Alternatively (and more concisely) in the client, you can just specify (tcp-connect ... :data "Hello")
which will also convert that string to binary before sending it out via babel
(a great octet/character conversion library), but for this example I wanted to show the process from character stream -> character stream.
Thank you. This helped.
Hi,
I wanted to implement a repl server over tcp.
(defun repl-server () (format t "Starting server.~%") (as:tcp-server nil 9003 ; nil is "0.0.0.0" (lambda (socket stream) (print (eval (read stream)) stream)) (lambda (err) (format t "listener event: ~a~%" err))) ;; catch sigint (as:signal-handler 2 (lambda (sig) (declare (ignore sig)) (as:exit-event-loop))))
This required me to define method (stream-read-char) (stream-unread-char) (stream-write-char) in tcp-streams. However I am now facing issues with the streams being binary and not understanding #\Newline etc. I want the streams to be flexible to accept character streams as well. How do I go about doing this?
-Nix