Created
May 22, 2025 23:23
-
-
Save antonl/77946ec7f0180e554cdf50497ac6e821 to your computer and use it in GitHub Desktop.
Socket-based chatbot
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 concurrent.futures import ThreadPoolExecutor | |
| import logging | |
| from datetime import datetime | |
| # Configure logging | |
| logging.basicConfig( | |
| level=logging.DEBUG, # Set the minimum logging level | |
| format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', # Set the format of log messages | |
| datefmt='%Y-%m-%d %H:%M:%S', # Set the format of the date and time | |
| ) | |
| def handle_client(connection, address, active_connections): | |
| log = logging.getLogger(str(address)) | |
| log.info(f"Connected {address}") | |
| is_initialized = False | |
| name = None | |
| connection.send("> Welcome to the Chat Room! What's your name?\n".encode()) | |
| buf = connection.recv(1024) | |
| if len(buf) > 0: | |
| name = buf.decode().strip() | |
| is_initialized = True | |
| log.info(f"Initialized client with name {name}") | |
| else: | |
| log.info(f"Failed to get {name}") | |
| while is_initialized: | |
| # read messages | |
| buf = connection.recv(1024) | |
| if len(buf) > 0: | |
| # handle broadcast | |
| log.info(f"Received message {buf}") | |
| timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") | |
| for _address, _connection in active_connections.items(): | |
| if _address == address: | |
| continue | |
| log.debug(f"Sending to {_address}") | |
| _connection.sendall(f"{timestamp} {name}: {buf.decode()}".encode()) | |
| else: | |
| # disconnect | |
| log.info(f"Disconnected.") | |
| break | |
| # cleanup | |
| active_connections.pop(address) | |
| def main(num_workers: int = 10): | |
| serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
| serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
| serversocket.bind(('localhost', 8888)) | |
| serversocket.listen(num_workers) # become a server socket, maximum 5 connections | |
| log = logging.getLogger("Started server") | |
| active_connections = {} | |
| with ThreadPoolExecutor() as pool: | |
| try: | |
| while True: | |
| connection, address = serversocket.accept() | |
| log.info(f"Connected client {address}") | |
| active_connections[address] = connection | |
| pool.submit(handle_client, connection=connection, address=address, active_connections=active_connections) | |
| except KeyboardInterrupt: | |
| return | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment