Appearance
Versuch Python Chat
Die Transportschicht ist zuständig für die Bereitstellung einer verbindungslose (Datagramm), oder verbindungsorientierten Kommunikation zwischen zwei Endpunkten. UDP (verbindungslos) und TCP (verbindungsorientiert) sind hierbei die dominanten Protokolle, welche für Datennetze eingesetzt werden.
Lektüre
Bitte lesen Sie folgende Abschnitte im Buch "Computernetzwerke"
- 6.4.1 Einführung in UDP
- 6.5.1 - 6.5.8 TCP
Chat über TCP
Folgen Sie dem Tutorial zu Python TCP hier bis zum Teil "Communication Breakdown ": https://realpython.com/python-sockets/.
Bauen Sie zu zweit eine einfache Chat Applikation in Python - orientieren Sie sich an diesem Beispiel: https://wiki.python.org/moin/TcpCommunication und dem Beispiel von Versuch: Raw Socket .
Gehen Sie wie folgt vor:
- Erstellen Sie zuerst einen Server, welcher auf Port
1337
hört.- Lesen Sie vom Port ...
- ... und geben Sie die Daten auf stdout aus.
- Verwenden Sie auf der Client seite
netcat
um dem Server daten zu senden. - Erstellen Sie nun in Python separat einen Client.
- Sie können die IP Adresse zuerst hardcoden.
- Senden Sie eine konstante Nachricht.
- Input von STDIN lesen
- Schauen Sie sich ein paar Beispiele hier an https://en.wikibooks.org/wiki/Python_Programming/Input_and_Output
- senden Sie nun bei jeder neuen Zeile den Input an den Server
- Implementieren Sie das einlesen von Input auch auf der Serverseite mittels einfachem Thread
- Folgen Sie dem Beispiel, dass Sie hier finden https://realpython.com/intro-to-python-threading/
Frage
- Was wäre anders, wenn Sie UDP anstatt TCP verwenden würden?
- Wie können Sie mehrere Clients gleichzeitig bedienen?
- Bonus: Implementieren Sie einen Multi-Client Chat
Beispiel UDP Client
py
#!/usr/bin/python3
import socket
import sys
PORT = 7890
def main():
print("Welcome to the chat client using Port {}".format(PORT))
client_sock = socket.socket(
socket.AF_INET,
socket.SOCK_DGRAM)
name, ip, msg = sys.argv
client_sock.sendto("{}".format(msg).encode(), (ip, PORT))
if __name__ == "__main__":
main()
Beispiel UDP Server
py
#!/usr/bin/python3
import socket
PORT = 7890
def main():
print("Welcome to the chat server! Using PORT: {}".format(PORT))
server_sock = socket.socket(
socket.AF_INET,
socket.SOCK_DGRAM)
server_sock.bind(("0.0.0.0", PORT))
while True:
msg, (ip, port) = server_sock.recvfrom(1024)
print("{}: {}".format(ip, msg.decode()))
if __name__ == "__main__":
main()
Beispiel TCP Client
py
import socket
from threading import Thread
PORT = 1337
LEN = 4096
def handle_send(sock: socket.socket):
try:
while 1:
msg = input("")
sock.send(msg.encode())
except Exception as e:
print(e)
pass
def main():
hostname = input("hostname of server: ")
print("connecting to {}".format(hostname))
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((hostname, PORT))
t = Thread(target=handle_send, args=(s,))
t.start()
try:
while 1:
data = s.recv(LEN)
print(data.decode())
except Exception as e:
print(e)
pass
if __name__ == "__main__":
main()
Beispiel TCP Server
py
import socket
import logging
from threading import Thread, Lock
HOST = '0.0.0.0'
PORT = 1337
LEN = 4096
lock = Lock()
peers = list()
class Peer:
conn: socket.socket
addr: object
def __init__(self, conn: socket.socket, addr: object):
self.conn = conn
self.addr = addr
def broadcast(peer: Peer, data):
if not data:
return
lock.acquire()
safe_peers = peers.copy()
lock.release()
for p in safe_peers:
if p is peer:
continue
try:
print(data)
p.conn.send('{}: {}\n'.format(p.addr[0], data).encode())
except:
logging.exception("error")
def handle_connetion(conn: socket.socket, addr: (str, int)):
peer = Peer(conn=conn, addr=addr)
lock.acquire()
peers.append(peer)
lock.release()
broadcast(peer, '[has entered the room]')
try:
while 1:
data = conn.recv(LEN)
if not data:
break
broadcast(peer, data.decode())
except:
logging.exception("error")
broadcast(peer, '[has left the room]')
print('shutting down connection for host: {}'.format(addr[0]))
conn.close()
lock.acquire()
peers.remove(peer)
lock.release()
def main():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
s.bind((HOST, PORT))
s.listen(20)
while 1:
conn, addr = s.accept()
print('handling new connection from: {}'.format(addr[0]))
thread = Thread(target=handle_connetion, args=(conn, addr))
thread.start()
if __name__ == '__main__':
main()
Beispiel TCP Server (farbige ausgabe )
py
#!/usr/bin/python3
import socket
PORT = 12000
peers = list()
def main():
print("Chat Server")
# erstellen einen Socket
# festlegen auf welcher IP wir hoehren
# receive auf socket
# print payload
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(("0.0.0.0", PORT))
while True:
msg, (ip, port) = server_socket.recvfrom(1024)
push = True
for v in peers:
(cip, cport) = v
if cip == ip and cport == port:
push = False
if push == True:
peers.append((ip, port))
print("{}@{}: {}".format(ip, port, msg.decode()))
for v in peers:
(cip, cport) = v
print("sending to {}:{}".format(cip, cport))
server_socket.sendto("\033[92m{}: {}".format(ip, msg.decode()).encode(), (cip, cport))
# an alle hosts weitergeben
class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKCYAN = '\033[96m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
if __name__ == '__main__':
main()