rk/LDN10/client.py
Gašper Dobrovoljc 885ce73d7e
LDN10
2024-05-26 18:10:13 +02:00

108 lines
3.1 KiB
Python

import json
import socket
import struct
import sys
import ssl
import threading
from datetime import datetime
PORT = 1234
HEADER_LENGTH = 2
def setup_SSL_context():
#uporabi samo TLS, ne SSL
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
# certifikat je obvezen
context.verify_mode = ssl.CERT_REQUIRED
#nalozi svoje certifikate
context.load_cert_chain(certfile="certs/janez_cert.crt", keyfile="certs/janez_private.key")
# nalozi certifikate CAjev (samopodp. cert.= svoja CA!)
context.load_verify_locations('certs/server_cert.crt')
# nastavi SSL CipherSuites (nacin kriptiranja)
context.set_ciphers('ECDHE-RSA-AES128-GCM-SHA256')
return context
def receive_fixed_length_msg(sock, msglen):
message = b''
while len(message) < msglen:
chunk = sock.recv(msglen - len(message)) # preberi nekaj bajtov
if chunk == b'':
raise RuntimeError("socket connection broken")
message = message + chunk # pripni prebrane bajte sporocilu
return message
def receive_json(sock):
# preberi glavo sporocila (v prvih 2 bytih je dolzina sporocila)
header = receive_fixed_length_msg(sock, HEADER_LENGTH)
message_length = struct.unpack("!H", header)[0] # pretvori dolzino sporocila v int
message = None
if message_length > 0: # ce je vse OK
message = receive_fixed_length_msg(sock, message_length) # preberi sporocilo
message = message.decode("utf-8")
message = json.loads(message)
return message
def send_json(sock, data):
data["time"] = datetime.now().strftime("%c")
# pretvori sporocilo v niz bajtov, uporabi UTF-8 kodno tabelo
encoded_data = json.dumps(data).encode("utf-8")
# ustvari glavo v prvih 2 bytih je dolzina sporocila (HEADER_LENGTH)
# metoda pack "!H" : !=network byte order, H=unsigned short
header = struct.pack("!H", len(encoded_data))
data = header + encoded_data # najprj posljemo dolzino sporocilo, sele nato sporocilo samo
sock.sendall(data)
def send_message(sock, message):
send_json(sock, {
"type": "message",
"data": message,
})
# message_receiver funkcija tece v loceni niti
def message_receiver():
while True:
msg_received = receive_json(sock)
msg_type = msg_received["type"]
data = msg_received["data"]
time = msg_received["time"]
match msg_type:
case "message":
username = msg_received["username"]
print(f'[{time}] [{username}] : {data}')
case "error":
print(f'Error: {data}')
# povezi se na streznik
print("[system] connecting to chat server ...")
my_ssl_ctx = setup_SSL_context()
sock = my_ssl_ctx.wrap_socket(socket.socket(socket.AF_INET, socket.SOCK_STREAM))
sock.connect(("localhost", PORT))
print("[system] connected!")
# zazeni message_receiver funkcijo v loceni niti
thread = threading.Thread(target=message_receiver)
thread.daemon = True
thread.start()
# pocakaj da uporabnik nekaj natipka in poslji na streznik
while True:
try:
msg_send = input("")
send_message(sock, msg_send)
except KeyboardInterrupt:
sys.exit()