aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Tuomi <jans.tuomi@gmail.com>2017-03-29 15:02:29 +0300
committerJan Tuomi <jans.tuomi@gmail.com>2017-03-29 15:09:07 +0300
commit13efdcbda6029486c81190881873836126569fc6 (patch)
tree0addc38bd57064ff722bac9cb67d5a9a73f8efd9
parentb2b42039493b0644c7b87fdcf9e61a245f069e5b (diff)
Initial commit
-rw-r--r--README.md72
-rwxr-xr-xserver.py91
-rw-r--r--test_message3
3 files changed, 166 insertions, 0 deletions
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