Sync
This commit is contained in:
parent
6f050a029e
commit
776bba907c
3887 changed files with 59894 additions and 7280 deletions
|
|
@ -1,47 +1,24 @@
|
|||
(defvar *clients* '()
|
||||
"This is a list of (socket :input status) which is used with
|
||||
`socket:socket-status' to test for data ready on a socket.")
|
||||
(ql:quickload (list :usocket))
|
||||
(defpackage :echo (:use :cl :usocket))
|
||||
(in-package :echo)
|
||||
|
||||
(defun echo-server (port)
|
||||
"Listen on `port' for new client connections and for data arriving on
|
||||
any existing client connections"
|
||||
(let ((server (socket:socket-server port)))
|
||||
(format t "Echo service listening on port ~a:~d~%"
|
||||
(socket:socket-server-host server)
|
||||
(socket:socket-server-port server))
|
||||
(unwind-protect
|
||||
(loop
|
||||
(when (socket:socket-status server 0 1)
|
||||
(echo-accept-client (socket:socket-accept server
|
||||
:external-format :dos
|
||||
:buffered t)))
|
||||
(when *clients*
|
||||
(socket:socket-status *clients* 0 1)
|
||||
(mapcar #'(lambda (client)
|
||||
(when (eq :input (cddr client))
|
||||
(echo-service-client (car client)))
|
||||
(when (eq :eof (cddr client))
|
||||
(echo-close-client (car client)))) *clients*)))
|
||||
(socket-server-close server))))
|
||||
(defun read-all (stream)
|
||||
(loop for char = (read-char-no-hang stream nil :eof)
|
||||
until (or (null char) (eq char :eof)) collect char into msg
|
||||
finally (return (values msg char))))
|
||||
|
||||
(defun echo-accept-client (socket)
|
||||
"Accept a new client connection and add it to the watch list."
|
||||
(multiple-value-bind
|
||||
(host port) (socket:socket-stream-peer socket)
|
||||
(format t "Connect from ~a:~d~%" host port))
|
||||
(push (list socket :input nil) *clients*))
|
||||
|
||||
(defun echo-service-client (socket)
|
||||
(let ((line (read-line socket nil nil)))
|
||||
(princ line socket)
|
||||
(finish-output socket)))
|
||||
|
||||
(defun echo-close-client (socket)
|
||||
"Close a client connection and remove it from the watch list."
|
||||
(multiple-value-bind
|
||||
(host port) (socket:socket-stream-peer socket)
|
||||
(format t "Closing connection from ~a:~d~%" host port))
|
||||
(close socket)
|
||||
(setq *clients* (remove socket *clients* :key #'car)))
|
||||
(defun echo-server (port &optional (log-stream *standard-output*))
|
||||
(let ((connections (list (socket-listen "127.0.0.1" port :reuse-address t))))
|
||||
(unwind-protect
|
||||
(loop (loop for ready in (wait-for-input connections :ready-only t)
|
||||
do (if (typep ready 'stream-server-usocket)
|
||||
(push (socket-accept ready) connections)
|
||||
(let* ((stream (socket-stream ready))
|
||||
(msg (concatenate 'string "You said: " (read-all stream))))
|
||||
(format log-stream "Got message...~%")
|
||||
(write-string msg stream)
|
||||
(socket-close ready)
|
||||
(setf connections (remove ready connections))))))
|
||||
(loop for c in connections do (loop while (socket-close c))))))
|
||||
|
||||
(echo-server 12321)
|
||||
|
|
|
|||
|
|
@ -1,38 +1,8 @@
|
|||
(defpackage :echo
|
||||
(:use :cl :usocket :cl-actors)
|
||||
(:import-from :cl-actors #:self))
|
||||
(in-package :echo)
|
||||
(defun echo-send (message port)
|
||||
(with-client-socket (sock str "127.0.0.1" port)
|
||||
(write-string message str)
|
||||
(force-output str)
|
||||
(when (wait-for-input sock :timeout 5)
|
||||
(coerce (read-all str) 'string))))
|
||||
|
||||
(defun read-line-no-hang (stream)
|
||||
"Reads a line from stream. Returns a partial line rather than hanging."
|
||||
(apply #'values
|
||||
(loop for char = (read-char-no-hang stream nil :eof)
|
||||
until (or (null char) (eq :eof char) (char= #\newline char))
|
||||
collect char into str
|
||||
finally (return (list (when str (coerce str 'string)) char)))))
|
||||
|
||||
(defactor tcp-server (server handler connections) (message)
|
||||
(loop for ready in (wait-for-input (cons server connections) :ready-only t)
|
||||
do (if (typep ready 'stream-server-usocket)
|
||||
(push (socket-accept server) connections)
|
||||
(multiple-value-bind (line last-char) (read-line-no-hang (socket-stream ready))
|
||||
(when (eq last-char :eof)
|
||||
(delete ready connections)
|
||||
(socket-close ready))
|
||||
(send handler ready line))))
|
||||
(send self nil)
|
||||
next)
|
||||
|
||||
(defactor echo-handler (stream) (socket input)
|
||||
(format stream "~a~%" input)
|
||||
(format (socket-stream socket) input)
|
||||
next)
|
||||
|
||||
(defparameter +port+ 12321)
|
||||
(defparameter *handler* (echo-handler :stream *standard-input*)
|
||||
"Accepts and deals with socket messages.")
|
||||
(defparameter *server*
|
||||
(tcp-server :server (socket-listen "127.0.0.1" +port+)
|
||||
:handler *handler*)
|
||||
"Listens on the specified address+port. Passes socket input to specified handler.")
|
||||
(send *server* :ping) ;; get the server started
|
||||
(echo-send "Hello echo!" 12321)
|
||||
|
|
|
|||
|
|
@ -1,22 +1,47 @@
|
|||
(defactor tcp-naive-client (sock) (message)
|
||||
(format (socket-stream sock) message)
|
||||
(force-output (socket-stream sock))
|
||||
next)
|
||||
(defvar *clients* '()
|
||||
"This is a list of (socket :input status) which is used with
|
||||
`socket:socket-status' to test for data ready on a socket.")
|
||||
|
||||
(defparameter *client* (tcp-naive-client :sock (socket-connect "127.0.0.1" +port+)))
|
||||
(defun echo-server (port)
|
||||
"Listen on `port' for new client connections and for data arriving on
|
||||
any existing client connections"
|
||||
(let ((server (socket:socket-server port)))
|
||||
(format t "Echo service listening on port ~a:~d~%"
|
||||
(socket:socket-server-host server)
|
||||
(socket:socket-server-port server))
|
||||
(unwind-protect
|
||||
(loop
|
||||
(when (socket:socket-status server 0 1)
|
||||
(echo-accept-client (socket:socket-accept server
|
||||
:external-format :dos
|
||||
:buffered t)))
|
||||
(when *clients*
|
||||
(socket:socket-status *clients* 0 1)
|
||||
(mapcar #'(lambda (client)
|
||||
(when (eq :input (cddr client))
|
||||
(echo-service-client (car client)))
|
||||
(when (eq :eof (cddr client))
|
||||
(echo-close-client (car client)))) *clients*)))
|
||||
(socket-server-close server))))
|
||||
|
||||
(send *client* "test~%test")
|
||||
;; should print
|
||||
;; test
|
||||
;; test
|
||||
(defun echo-accept-client (socket)
|
||||
"Accept a new client connection and add it to the watch list."
|
||||
(multiple-value-bind
|
||||
(host port) (socket:socket-stream-peer socket)
|
||||
(format t "Connect from ~a:~d~%" host port))
|
||||
(push (list socket :input nil) *clients*))
|
||||
|
||||
(send *client* "test")
|
||||
;; should print
|
||||
;; test
|
||||
(defun echo-service-client (socket)
|
||||
(let ((line (read-line socket nil nil)))
|
||||
(princ line socket)
|
||||
(finish-output socket)))
|
||||
|
||||
(defparameter *client2* (tcp-naive-client :sock (socket-connect "127.0.0.1" +port+)))
|
||||
(defun echo-close-client (socket)
|
||||
"Close a client connection and remove it from the watch list."
|
||||
(multiple-value-bind
|
||||
(host port) (socket:socket-stream-peer socket)
|
||||
(format t "Closing connection from ~a:~d~%" host port))
|
||||
(close socket)
|
||||
(setq *clients* (remove socket *clients* :key #'car)))
|
||||
|
||||
(send *client2* "woo!")
|
||||
;; should print
|
||||
;; woo!
|
||||
;; despite the fact that *client* isn't reading anything, and didn't terminate its last message with a newline
|
||||
(echo-server 12321)
|
||||
|
|
|
|||
33
Task/Echo-server/REALbasic/echo-server.realbasic
Normal file
33
Task/Echo-server/REALbasic/echo-server.realbasic
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
Class EchoSocket
|
||||
Inherits TCPSocket
|
||||
Sub DataAvailable()
|
||||
If Instr(Me.LookAhead, EndofLine.Windows) > 0 Then
|
||||
Dim data As String = Me.ReadAll
|
||||
Dim lines() As String = Split(data, EndofLine.Windows)
|
||||
For i As Integer = 0 To Ubound(lines)
|
||||
Me.Write(lines(i) + EndOfLine.Windows)
|
||||
Print(lines(i))
|
||||
Next
|
||||
End If
|
||||
End Sub
|
||||
End Class
|
||||
|
||||
Class EchoServer
|
||||
Inherits ServerSocket
|
||||
Function AddSocket() As TCPSocket
|
||||
Return New EchoSocket
|
||||
End Function
|
||||
End Class
|
||||
|
||||
Class App
|
||||
Inherits ConsoleApplication
|
||||
Function Run(args() As String) As Integer
|
||||
Listener = New EchoServer
|
||||
Listener.Port = 12321
|
||||
Listener.Listen()
|
||||
While True
|
||||
DoEvents() 'pump the event loop
|
||||
Wend
|
||||
End Function
|
||||
Private Listener As EchoListener
|
||||
End Class
|
||||
Loading…
Add table
Add a link
Reference in a new issue