-
-
Save shortsightedsid/71cf34282dfae0dd2528 to your computer and use it in GitHub Desktop.
; Short guide to TCP/IP Client/Server programming in Common Lisp using usockets | |
; | |
; The main reason for this guide is because there are very few examples that | |
; explain how to get started with socket programming with Common Lisp that I | |
; could understand. After spending a day trying, I finally came up with a small | |
; bit of code that makes it easy to understand the basics. I've written this | |
; primarily for myself, but should help others get started as well. | |
; As usual, we will use quicklisp to load usocket. | |
(ql:quickload "usocket") | |
; Now we need to create a server. There are 2 primary functions that we need | |
; to call. usocket:socket-listen and usocket:socket-accept. | |
; | |
; usocket:socket-listen binds to a port and listens on it. It returns a socket | |
; object. We need to wait with this object until we get a connection that we | |
; accept. That's where usocket:socket-accept comes in. It's a blocking call | |
; that returns only when a connection is made. This returns a new socket object | |
; that is specific to that connection. We can then use that connection to | |
; communicate with our client. | |
; | |
; So, what were the problems I faced due to my mistakes? | |
; Mistake 1 - My initial understanding was that socket-accept would return | |
; a stream object. NO.... It returns a socket object. In hindsight, its correct | |
; and my own mistake cost me time. So, if you want to write to the socket, you | |
; need to actually get the corresponding stream from this new socket. The socket | |
; object has a stream slot and we need to explicitly use that. And how does one | |
; know that? (describe connection) is your friend! | |
; | |
; Mistake 2 - You need to close both the new socket and the server socket. | |
; Again this is pretty obvious but since my initial code was only closing | |
; the connection, I kept running into a socket in use problem. Of course | |
; one more option is to reuse the socket when we listen. | |
; | |
; Once you get past these mistakes, it's pretty easy to do the rest. Close | |
; the connections and the server socket and boom you are done! | |
(defun create-server (port) | |
(let* ((socket (usocket:socket-listen "127.0.0.1" port)) | |
(connection (usocket:socket-accept socket :element-type 'character))) | |
(unwind-protect | |
(progn | |
(format (usocket:socket-stream connection) "Hello World~%") | |
(force-output (usocket:socket-stream connection))) | |
(progn | |
(format t "Closing sockets~%") | |
(usocket:socket-close connection) | |
(usocket:socket-close socket))))) | |
; Now for the client. This part is easy. Just connect to the server port | |
; and you should be able to read from the server. The only silly mistake I | |
; made here was to use read and not read-line. So, I ended up seeing only a | |
; "Hello" from the server. I went for a walk and came back to find the issue | |
; and fix it. | |
(defun create-client (port) | |
(let ((socket (usocket:socket-connect "127.0.0.1" port :element-type 'character))) | |
(unwind-protect | |
(progn | |
(usocket:wait-for-input socket) | |
(format t "~A~%" (read-line (usocket:socket-stream socket)))) | |
(usocket:socket-close socket)))) | |
; So, how do you run this? You need two REPLs - one for the server | |
; and one for the client. Load this file in both REPLs. Create the | |
; server in the first REPL. | |
; (create-server 12321) | |
; Now you are ready to run the client on the second REPL | |
; (create-client 12321) | |
; Voila! You should see "Hello World" on the second REPL. | |
; ; Also see | |
; 1. Short Guide on UDP/IP | |
; - https://gist.github.com/shortsightedsid/a760e0d83a9557aaffcc |
Hi, I'm a maintainer of usocket, can I incorporate your material as a section of the official user manual (in progress)? Of course your name will appear as the author.
@binghe I received the email notification. You are probably referring to the gist on top. But given I too offer an example and so does @traut in this threat just before my comment, which are the last two here, I just want to make sure. So, which of the three examples are you referring to and is it that you want to use?
Sorry, to be clear, I was asking @shortsightedsid for his cl-tcpip.lisp
and cl-udpip.lisp
, because I found they also have good inline documents.
Sorry, to be clear, I was asking @shortsightedsid for his
cl-tcpip.lisp
andcl-udpip.lisp
, because I found they also have good inline documents.
No big deal. I thought so. Just wanted to make sure ;)
Hello, hoping it may be of interest, I share this article:
https://www.cybergigi.com/elenco-url-radio-italiane-sul-web-come-trovare-i-link-diretti-di-ip-streaming/
Hi, I'm a maintainer of usocket, can I incorporate your material as a section of the official user manual (in progress)? Of course your name will appear as the author.