Skip to content

Commit 2f6da6e

Browse files
committed
add chat application tutorial
1 parent 7fdcf8d commit 2f6da6e

File tree

5 files changed

+131
-0
lines changed

5 files changed

+131
-0
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
110110
- [How to Work with JSON Files in Python](https://www.thepythoncode.com/article/working-with-json-files-in-python). ([code](python-standard-library/working-with-json))
111111
- [How to Use Regular Expressions in Python](https://www.thepythoncode.com/article/work-with-regular-expressions-in-python). ([code](python-standard-library/regular-expressions))
112112
- [Logging in Python](https://www.thepythoncode.com/article/logging-in-python). ([code](python-standard-library/logging))
113+
- [How to Make a Chat Application in Python](https://www.thepythoncode.com/article/make-a-chat-room-application-in-python). ([code](python-standard-library/chat-application))
113114

114115
- ### [Using APIs](https://www.thepythoncode.com/topic/using-apis-in-python)
115116
- [How to Automate your VPS or Dedicated Server Management in Python](https://www.thepythoncode.com/article/automate-veesp-server-management-in-python). ([code](general/automating-server-management))

Diff for: python-standard-library/chat-application/README.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# [How to Make a Chat Application in Python](https://www.thepythoncode.com/article/make-a-chat-room-application-in-python)
2+
To run this:
3+
- `pip3 install -r requirements.txt`
4+
- Run `server.py` first to initialize the server.
5+
- Run one or more `client.py` instances and chat!
6+
- If you want to run `client.py` from another machine, make sure you change `SERVER_HOST` in `client.py` to the server's IP address.

Diff for: python-standard-library/chat-application/client.py

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import socket
2+
import random
3+
from threading import Thread
4+
from datetime import datetime
5+
from colorama import Fore, init, Back
6+
7+
# init colors
8+
init()
9+
10+
# set the available colors
11+
colors = [Fore.BLUE, Fore.CYAN, Fore.GREEN, Fore.LIGHTBLACK_EX,
12+
Fore.LIGHTBLUE_EX, Fore.LIGHTCYAN_EX, Fore.LIGHTGREEN_EX,
13+
Fore.LIGHTMAGENTA_EX, Fore.LIGHTRED_EX, Fore.LIGHTWHITE_EX,
14+
Fore.LIGHTYELLOW_EX, Fore.MAGENTA, Fore.RED, Fore.WHITE, Fore.YELLOW
15+
]
16+
17+
# choose a random color for the client
18+
client_color = random.choice(colors)
19+
20+
# server's IP address
21+
# if the server is not on this machine,
22+
# put the private (network) IP address (e.g 192.168.1.2)
23+
SERVER_HOST = "127.0.0.1"
24+
SERVER_PORT = 5002 # server's port
25+
separator_token = "<SEP>" # we will use this to separate the client name & message
26+
27+
# initialize TCP socket
28+
s = socket.socket()
29+
print(f"[*] Connecting to {SERVER_HOST}:{SERVER_PORT}...")
30+
# connect to the server
31+
s.connect((SERVER_HOST, SERVER_PORT))
32+
print("[+] Connected.")
33+
# prompt the client for a name
34+
name = input("Enter your name: ")
35+
36+
def listen_for_messages():
37+
while True:
38+
message = s.recv(1024).decode()
39+
print("\n" + message)
40+
41+
# make a thread that listens for messages to this client & print them
42+
t = Thread(target=listen_for_messages)
43+
# make the thread daemon so it ends whenever the main thread ends
44+
t.daemon = True
45+
# start the thread
46+
t.start()
47+
48+
while True:
49+
# input message we want to send to the server
50+
to_send = input()
51+
# a way to exit the program
52+
if to_send.lower() == 'q':
53+
break
54+
# add the datetime, name & the color of the sender
55+
date_now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
56+
to_send = f"{client_color}[{date_now}] {name}{separator_token}{to_send}{Fore.RESET}"
57+
# finally, send the message
58+
s.send(to_send.encode())
59+
60+
# close the socket
61+
s.close()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
colorama

Diff for: python-standard-library/chat-application/server.py

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import socket
2+
from threading import Thread
3+
4+
# server's IP address
5+
SERVER_HOST = "0.0.0.0"
6+
SERVER_PORT = 5002 # port we want to use
7+
separator_token = "<SEP>" # we will use this to separate the client name & message
8+
9+
# initialize list/set of all connected client's sockets
10+
client_sockets = set()
11+
# create a TCP socket
12+
s = socket.socket()
13+
# make the port as reusable port
14+
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
15+
# bind the socket to the address we specified
16+
s.bind((SERVER_HOST, SERVER_PORT))
17+
# listen for upcoming connections
18+
s.listen(5)
19+
print(f"[*] Listening as {SERVER_HOST}:{SERVER_PORT}")
20+
21+
def listen_for_client(cs):
22+
"""
23+
This function keep listening for a message from `cs` socket
24+
Whenever a message is received, broadcast it to all other connected clients
25+
"""
26+
while True:
27+
try:
28+
# keep listening for a message from `cs` socket
29+
msg = cs.recv(1024).decode()
30+
except Exception as e:
31+
# client no longer connected
32+
# remove it from the set
33+
print(f"[!] Error: {e}")
34+
client_sockets.remove(cs)
35+
else:
36+
# if we received a message, replace the <SEP>
37+
# token with ": " for nice printing
38+
msg = msg.replace(separator_token, ": ")
39+
# iterate over all connected sockets
40+
for client_socket in client_sockets:
41+
# and send the message
42+
client_socket.send(msg.encode())
43+
44+
45+
while True:
46+
# we keep listening for new connections all the time
47+
client_socket, client_address = s.accept()
48+
print(f"[+] {client_address} connected.")
49+
# add the new connected client to connected sockets
50+
client_sockets.add(client_socket)
51+
# start a new thread that listens for each client's messages
52+
t = Thread(target=listen_for_client, args=(client_socket,))
53+
# make the thread daemon so it ends whenever the main thread ends
54+
t.daemon = True
55+
# start the thread
56+
t.start()
57+
58+
# close client sockets
59+
for cs in client_sockets:
60+
cs.close()
61+
# close server socket
62+
s.close()

0 commit comments

Comments
 (0)