-
-
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.lispandcl-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.