Last active
October 1, 2019 12:36
-
-
Save gordinmitya/349f4abdc6b16dc163fa39b55544fd34 to your computer and use it in GitHub Desktop.
Simple python socket chat. One thread per client. Use telnet to join.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import socket | |
from threading import Thread | |
clients = [] | |
# Thread to listen one particular client | |
class ClientListener(Thread): | |
def __init__(self, name: str, sock: socket.socket): | |
super().__init__(daemon=True) | |
self.sock = sock | |
self.name = name | |
# add 'me> ' to sended message | |
def _clear_echo(self, data): | |
# \033[F – symbol to move the cursor at the beginning of current line (Ctrl+A) | |
# \033[K – symbol to clear everything till the end of current line (Ctrl+K) | |
self.sock.sendall('\033[F\033[K'.encode()) | |
data = 'me> '.encode() + data | |
# send the message back to user | |
self.sock.sendall(data) | |
# broadcast the message with name prefix eg: 'u1> ' | |
def _broadcast(self, data): | |
data = (self.name + '> ').encode() + data | |
for u in clients: | |
# send to everyone except current client | |
if u == self.sock: | |
continue | |
u.sendall(data) | |
# clean up | |
def _close(self): | |
clients.remove(self.sock) | |
self.sock.close() | |
print(self.name + ' disconnected') | |
def run(self): | |
while True: | |
# try to read 1024 bytes from user | |
# this is blocking call, thread will be paused here | |
data = self.sock.recv(1024) | |
if data: | |
self._clear_echo(data) | |
self._broadcast(data) | |
else: | |
# if we got no data – client has disconnected | |
self._close() | |
# finish the thread | |
return | |
def main(): | |
next_name = 1 | |
# AF_INET – IPv4, SOCK_STREAM – TCP | |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
# reuse address; in OS address will be reserved after app closed for a while | |
# so if we close and imidiatly start server again – we'll get error | |
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
# listen to all interfaces at 8800 port | |
sock.bind(('', 8800)) | |
sock.listen() | |
while True: | |
# blocking call, waiting for new client to connect | |
con, addr = sock.accept() | |
clients.append(con) | |
name = 'u' + str(next_name) | |
next_name += 1 | |
print(str(addr) + ' connected as ' + name) | |
# start new thread to deal with client | |
ClientListener(name, con).start() | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment