Let’s Write a Chat App in Python

Saurabh Chaturvedi
Nov 22, 2017 · 9 min read

Tkinter + sockets in less than 150 lines of code

Image for post
Image for post
It’s Always Good to Have a Conversation!

Not too frequently, you happen to create something astonishingly simple yet fun to use thing, and you just can’t wait to share it with the world.

That’s exactly what happened to me, and indeed I’m here to share how I made a simple chat app with quite concise Python code. What’s more; I’ve implemented the code without any third party dependencies! So let’s just dive in!

First, I created a chat server through which can recieve incoming requests from clients wanting to communicate. For this, I used good ole’ sockets and a bit of multithreading. Using frameworks like Twisted and SocketServer was an option, but that seemed to be an overkill to me for a software as simple as ours.

The Server

Image for post
Image for post

Here’s how we begin our server script (for this app, there are just two scripts: one for server and another for client):

We will be using TCP sockets for this purpose, and therefore we use and flags. We use them over UDP sockets because they’re more telephonic, where the recipient has to approve the incoming connection before communication begins, and UDP sockets are more post-mail sort of thing (anyone can send a mail to any recipient whose address s/he knows), so they don’t really require an establishment of connection before communication can happen. Clearly, TCP suit more to our purpose than UDP sockets, therefore we use them. You can know more about sockets here.

After imports, we set up some constants for later use:

Now, we break our task of serving into accepting new connections, broadcasting messages and handling particular clients. Let’s begin with accepting connections:

This is just a loop that waits forever for incoming connections and as soon as it gets one, it logs the connection (prints some of the connection details) and sends the connected client a welcome message. Then it stores the client’s address in the dictionary and later starts the handling thread for that client. Of course, we haven’t yet defined the target function for that, but here’s how we do it:

Naturally, after we send the new client the welcoming message, it will reply with the name s/he wants to use for further communication. In the function, the first task we do is we save this name, and then send another message to the client, regarding further instructions. After this comes the main loop for communication: here we recieve further messages from the client and if a message doesn’t contain instructions to quit, we simply broadcast the messsage to other connected clients (we’ll be defining the broadcast method in a moment). If we do encounter a message with exit instructions (i.e., the client sends a ), we echo back the same message to the client (it triggers close action on the client side) and then we close the connection socket for it. We then do some cleanup by deleting the entry for the client, and finally give a shoutout to other connected people that this particular person has left the conversation.

Now comes our function:

This is pretty much self-explanatory; it simply sends the to all the connected clients, and prepends an optional if necessary. We do pass a to in our function, and we do it so that people can see exactly who is the sender of a particular message.

That was all the required functionalities for our server. Finally, we put in some code for starting our server and listening for incoming connections:

We so that the main script waits for it to complete and doesn’t jump to the next line, which closes the server.

This completes our server script, which is presented in the following gist (for those who’re reading this on smartphones, visit this link for the complete server code):

The Client

Image for post
Image for post

This is more fun beause we’ll be writing a GUI! We use Tkinter, Python’s “batteries included” GUI building tool for our purpose. Let’s do some imports first:

Now we’ll write functions for handling sending and receiving of messages. We start with receive:

Why an infinite loop again? Because we’ll be receiving messages quite non-deterministically, and independent of how and when we send the messages. We don’t want this to be a walkie-talkie chat app which can only either send or receive at a time; we want to receive messages when we can, and send them when we want. The functionality within the loop is pretty straightforward; the is the blocking part. It stops execution until it receives a message, and when it does, we move ahead and append the message to . We will soon define , which is basically a Tkinter feature for displaying the list of messages on the screen.

Next, we define the function:

We’re using as an argument because it is implicitly passed by Tkinter when the button on the GUI is pressed. is the input field on the GUI, and therefore we extract the message to be sent usin g . After that, we clear the input field and then send the message to the server, which, as we’ve seen before, broadcasts this message to all the clients (if it’s not an exit message). If it is an exit message, we close the socket and then the GUI app (via )

We define one more function, which will be called when we choose to close the GUI window. It is a sort of cleanup-before-close function and shall close the socket connection before the GUI closes:

This sets the input field to and then calls , which then works as expected. Now we start building the GUI, in the main namespace (i.e., outside any function). We start by defining the top-level widget and set its title:

Then we create a frame for holding the list of messages. Next, we create a string variable, primarily for storing the value we get from the input field (which we shall define soon). We set that variable to to prompt the user for writing their message. After that, we create a scrollbar for scrolling through this message frame. Here’s the code:

Now we define the message list which will be stored in and then pack in (at the appropriate places) all the stuff we’ve created till now:

After this, we create the input field for the user to input their message, and bind it to the string variable defined above. We also bind it to the function so that whenever the user presses return, the message is sent to the server. Next, we create the send button if the user wishes to send their messages by clicking on it. Again, we bind the clicking of this button to the function. And yes, we also pack all this stuff we created just now. Furthermore, don’t forget to make use of the cleanup function which should be called when the user wishes to close the GUI window. We do that by using the method of . Here’s the code for all of this:

(Almost) done. We haven’t yet written code for connecting to the server. For that, we have to ask the user for the server’s address. I’ve done that by simply using , so the user is greeted with some command line prompt asking for host address before the GUI begins. It may be a little inconvenient, and you can add GUI for that, but I leave that to you as homework 🙂. Here’s my code:

Once we get the address and create a socket to connect to it, we start the thread for receiving messages, and then the main loop for our GUI application:

That’s it! We’ve coded our chat application. Again, the complete client script is given in the following gist (and for readers on their smartphones, here’s the link to the gist):

Demo

This feels great to be tested on multiple computers. You can, of course, run the server and the client on the same machine for testing (using for in your client), but seeing the communication happen in realtime among different computers feels awesome. The server script will log which IP addresses are accessing it, and the client script will generate a GUI (after asking for the host address) similar to the following screenshots:

Image for post
Image for post
Client GUI
Image for post
Image for post
Another Client Connected to the Same Server

Honestly speaking, the GUI looks good considering the number of lines of Python code behind it, but not great! I leave it to you to make this look better (and more intuitive), perhaps by making a left-right chat interface like Facebook’s Messenger. You may even use third-party libraries like Kivy for more beauty and cross-platform portability, or a Web interface instead - post your ideas in the comments. Finally, thanks for bearing with me and reading till the last character! I applaud your patience 🙂.

P.S: For my other projects (some smaller and others much larger), visit my GitHub profile.

Furthermore, I’m new to blogging, so constructive criticism is not only needed, but very much wanted! I’m open to better writing styles, techniques and pedagogy — feel free to mention them in the comments.

Image for post
Image for post
Did you like the read? Medium doesn’t offer partner program in my country―so I ask people to buy me coffee instead.
Image for post
Image for post

This story is published in The Startup, where 263,100+ people come together to read Medium’s leading stories on entrepreneurship.

Subscribe to receive our top stories here.

Image for post
Image for post

The Startup

Medium's largest active publication, followed by +719K people. Follow to join our community.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store