From 13efdcbda6029486c81190881873836126569fc6 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Wed, 29 Mar 2017 15:02:29 +0300 Subject: Initial commit --- README.md | 72 +++++++++++++++++++++++++++++++++++++++++++++++ server.py | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ test_message | 3 ++ 3 files changed, 166 insertions(+) create mode 100644 README.md create mode 100755 server.py create mode 100644 test_message diff --git a/README.md b/README.md new file mode 100644 index 0000000..d3be80e --- /dev/null +++ b/README.md @@ -0,0 +1,72 @@ +# Chat-palvelin + +Chat-palvelin tietoliikennekurssin työksi. + +## Versiot +* Python 3.5 +sekä Python-kirjastot +* socket (latest) +* threading (latest) + +## Suunnitelma + +Projektin tavoite on tehdä palvelin-asiakas-keskusteluohjelma, joka tukee viestien lähettämistä, palvelimelle yhdistämistä ja sieltä poistumista. + +## Protokolla + +Ohjelmalle on suunniteltu TCP:n päälle viestintäprotokolla. + +### Palvelimelta asiakkaalle + +#### BROADCAST +Välittää asiakkaan lähettämän viestin muille asiakkaille. + +``` +BROADCAST\n +user_name\n +message content\n +\0 +``` + +### Asiakkaalta palvelimelle + +#### CONNECT +Ilmoittaa yhdistäneen asiakkaan käyttäjänimen. + +``` +CONNECT\n +user_name\n +\0 +``` + +#### DISCONNECT +Ilmoittaa asiakkaan katkaisevan yhteyden. + +``` +DISCONNECT\n +user_name\n +\0 +``` + +#### MESSAGE +Lähettää viestin palvelimelle välitettäväksi muille asiakkaille BROADCASTilla. + +``` +MESSAGE\n +user_name\n +message content\n +\0 +``` + +#### KEEPALIVE +Ylläpitää yhteyttä palvelimeen, jos käyttäjä ei ole aktiivinen. Lähetetään tasaisin väliajoin. + +``` +KEEPALIVE\n +user_name\n +\0 +``` + +## Tekijät + +Jan Tuomi ja Toni Miilunpalo diff --git a/server.py b/server.py new file mode 100755 index 0000000..9957710 --- /dev/null +++ b/server.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 + +import socket +import threading +from functools import partial +from datetime import datetime + +HOST = "0.0.0.0" +PORT = 5000 +DEBUG = True +def debug(string): + if (DEBUG): + print("{} DEBUG: {}".format(datetime.now(), string)) + +def parse_message(text): + rows = text.split('\n') + if (len(rows) < 3): + return None + + try: + command = rows[0].strip() + username = rows[1].strip() + body = rows[2].strip() + except: + return None + + debug("Command '{}' from '{}' with body '{}'".format(command, username, body)) + return (command, username, body) + +def broadcast(message, username, recipients): + debug("Broadcasting message '{}'".format(message)) + for rec in recipients: + response = "BROADCAST\n{}\n{}\n".format(username, message) + try: + rec.send(response.encode()) + except OSError: + debug("ERROR: Couldn't broadcast message to {}".format(str(rec))) + +def do_command(command, username, body, bc): + if command == "CONNECT": + bc("User {} has connected".format(username), username) + elif command == "DISCONNECT": + bc("User {} has disconnected".format(username), username) + elif command == "MESSAGE": + bc("{}: {}".format(username, body), username) + elif command == "KEEPALIVE": + pass + else: + debug("Unknown command '{}' from user '{}'".format(command, username)) + +def keep_connection(conn, addr, connections): + debug("Connection from: {}".format(addr)) + + broadcast_fun = partial(broadcast, recipients=connections) + while True: + data = conn.recv(1024).decode() + + if not data: + break + + data_tuple = parse_message(str(data)) + if not data_tuple: + debug("Failed to parse data from client") + continue + + command, username, body = data_tuple + do_command(command, username, body, broadcast_fun) + + conn.close() + connections.remove(conn) + debug("Closed connection to: {}".format(addr)) + +def main(): + mySocket = socket.socket() + mySocket.bind((HOST, PORT)) + + connections = [] + threads = [] + mySocket.listen(1) + running = True + + while running: + conn, addr = mySocket.accept() + t = threading.Thread(target=keep_connection, args=(conn, addr, connections)) + threads.append(t) + connections.append(conn) + t.daemon = True + t.start() + +if __name__ == '__main__': + main() diff --git a/test_message b/test_message new file mode 100644 index 0000000..7f7d4f4 --- /dev/null +++ b/test_message @@ -0,0 +1,3 @@ +MESSAGE +teppo_tulppu +asd -- cgit v1.3