Python sockets suddenly recieving different fernet key - python

So i am trying to make a message application with tkinter gui. I have a client and a server, which is currently just running locally.
So i i generate a fernet key which i first send to the server, so we can both encrypt with the same key (i know this probably should be encrypted when i send it).
The first time i call the client.connect() it works fine, gets the key and checks if the roomId exists. If it does not it spits out an error and all is fine. However if I try again, calling client.connect() the fernet key which the server receives gets all messed up.
First time
Client
b'Nwb0wki6ydmeZgEyMqo0ZFvvPm_grlpnYicjhCMZTMg='
b'Nwb0wki6ydmeZgEyMqo0ZFvvPm_grlpnYicjhCMZTMg='
b'Nwb0wki6ydmeZgEyMqo0ZFvvPm_grlpnYicjhCMZTMg='
Server
b'Nwb0wki6ydmeZgEyMqo0ZFvvPm_grlpnYicjhCMZTMg='
As you can see the first time it works fine
Second time
Client
b'tq2uBDFfpV0vAmDNpJKmA-87ElJqa5Unsme7OGCTG80='
b'tq2uBDFfpV0vAmDNpJKmA-87ElJqa5Unsme7OGCTG80='
b'tq2uBDFfpV0vAmDNpJKmA-87ElJqa5Unsme7OGCTG80='
Server
b'tq2uBDFfpV0vAmDNpJKmA-87ElJqa5Unsme7OGCTG80=gAAAAABfmnNNS9XplQlqNf3-7vlEgk-VAHsq6EIJaWTUhLyaCqIictM7v5rnh6_dMhKKNvGc3otMi08SEhtmgfyK3KSXD6SckOk9abFGW6-KS36b3jtThBdmid1EXxCmu7B0IgmulmZF_K0VhKAiOEty74nqZ_YLkDzfaaKHzXnPsfx-39ssKSA='
Even though i am calling the exact same method, and its making a new connecting, and it seems to be sending a perfectly fine key, the server recievieves something totally different. And yes i only have one client connected to the server
Client connection function
def connect(self, username="joe", roomId="12346", host="127.0.0.1", port="9001"):
self.host = host
self.port = int(port)
self.key = fernet.Fernet.generate_key()
print(self.key)
self.username = username
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect((self.host, self.port))
self.connected = True
print(self.key)
self.sock.send(self.key)
print(self.key)
print("sendte key")
self.sock.sendall(Encryption().encryptMsg(self.username, self.key))
print("sendte username")
self.sock.sendall(Encryption().encryptMsg(roomId, self.key))
print(roomId)
print("sendte roomId")
msg = self.sock.recv(1024)
msg = Encryption().decryptMsg(msg, self.key)
print(msg)
if msg["msg"] == False:
self.disconnect()
return False
self.clientId, self.roomId = msg["msg"]
self.thread = threading.Thread(target=self.listen)
self.thread.start()
print("Started listening")
print(self.username, self.roomId, self.clientId)
return True
except Exception as e:
print(e)
self.disconnect()
return False
def disconnect(self):
print("lukker sock")
self.sock.shutdown(socket.SHUT_RDWR)
Server receiving function
def run(self):
self.sock.bind((self.host, self.port))
self.sock.listen(self.listenInt)
while True:
# try:
conn, addr = self.sock.accept()
print("Got connection from: ", addr)
newCon = threading.Thread(
target=self.handleConnection, args=(conn, addr))
newCon.start()
self.sock.close()
def handleConnection(self, conn, addr):
print("startet handler")
key = conn.recv(1024)
print("fikk key")
print(key)
username = Encryption().decryptMsg(conn.recv(1024), key)["msg"]
print("fikk username")
print(username)
roomId = int(Encryption().decryptMsg(conn.recv(1024), key)["msg"])
print("fikk roomid")
print(roomId)
print(self.rooms)
if roomId == 0:
room = Room(self)
roomId = room.roomId
self.rooms[roomId] = room
print("lagde rom")
elif roomId not in self.rooms:
print("finner ikke rom")
conn.sendall(Encryption().encryptMsg(False, key))
print("sendte false")
conn.close()
return
room = self.rooms[roomId]
newCon = threading.Thread(
target=serverConnection, args=(conn, addr, key, room, username))
newCon.start()

Related

Python Socket Encoding and Decoding Client Data

I'm trying to create a message server type of thing. After connecting to the server client-side and attempting to type in a username, it gives the error:
"a bytes-like object is required, not 'str'"
And I wasn't sure If I was mishandling the encoding and decoding functions or not.
import socket, time, sys, threading
class Server:
def __init__(self, port):
while True:
try:
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.port = port
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind(('127.0.0.1',port))
self.clients = []
self.usernames = []
print('Successfully bound socket!')
break
except:
print('Error binding, retrying....')
time.sleep(5)
def close(self):
self.socket.close()
def commands(self):
while True:
command = input()
if command.lower() in ['exit', 'end', 'quit', 'q']:
print('Closing Session.....')
server.close(), sys.exit()
def broadcast(self, message):
for client in self.clients:
client.send(message)
def handle(self, client):
while True:
try:
message = client.recv(1024)
server.broadcast(message)
except:
index = self.clients.index(client)
self.clients.remove(client)
client.close()
username = self.usernames[index]
server.broadcast(f'{username.decode("ascii")} has left!')
self.usernames.remove(username)
break
def receive(self, client, addr):
while True:
print(f'New Socket Connection: {addr}')
try:
client.send('USERNAME: '.encode('ascii'))
username = client.recv(1024).decode('ascii')
self.usernames.append(username)
self.clients.append(client)
print(f'Username is: {username}')
server.broadcast(f'{username.encode("ascii")} has connected.')
client.send('Connected to the server!'.encode('ascii'))
thread = threading.Thread(target=handle, args=(client,))
thread.start()
except Exception as e:
print(e)
print('Closed early! (Or wrong values entered!)')
socket.close()
print(f'Client {addr} closed.')
client.send()
def listen(self):
self.socket.listen(5)
print('Listening for new connections....')
while True:
client, addr = self.socket.accept()
client.settimeout(60)
server.receive(client, addr)
server = Server(4545)
try:
server.listen()
except:
server.close()
The problem occurs from the receive function:
def receive(self, client, addr):
while True:
print(f'New Socket Connection: {addr}')
try:
client.send('USERNAME: '.encode('ascii'))
username = client.recv(1024).decode('ascii')
self.usernames.append(username)
self.clients.append(client)
print(f'Username is: {username}')
server.broadcast(f'{username.encode("ascii")} has connected.')
client.send('Connected to the server!'.encode('ascii'))
thread = threading.Thread(target=handle, args=(client,))
thread.start()
except Exception as e:
print(e)
print('Closed early! (Or wrong values entered!)')
socket.close()
print(f'Client {addr} closed.')
client.send()
Have a look at this part of code :
def receive(self, client, addr):
while True:
#[...]
server.broadcast(f'{username.encode("ascii")} has connected.')
You're just encoding the username but not the complete string!
So it should be something like this :
#[...]
server.broadcast(f'{username} has connected.'.encode("ascii"))
#[...]
Here's the final working code:
import socket, time, sys, threading
class Server:
def __init__(self, port):
while True:
try:
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.port = port
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind(('127.0.0.1',port))
self.clients = []
self.usernames = []
print('Successfully bound socket!')
break
except:
print('Error binding, retrying....')
time.sleep(5)
def close(self):
self.socket.close()
def commands(self):
while True:
command = input()
if command.lower() in ['exit', 'end', 'quit', 'q']:
print('Closing Session.....')
server.close(), sys.exit()
def broadcast(self, message):
for client in self.clients:
client.send(message)
def handle(self, client):
while True:
try:
message = client.recv(1024)
server.broadcast(message)
except:
index = self.clients.index(client)
self.clients.remove(client)
client.close()
username = self.usernames[index]
server.broadcast(f'{username.decode("ascii")} has left!')
self.usernames.remove(username)
break
def receive(self, client, addr):
while True:
print(f'New Socket Connection: {addr}')
try:
client.send('USERNAME: '.encode('ascii'))
username = client.recv(1024).decode('ascii')
self.usernames.append(username)
self.clients.append(client)
print(f'Username is: {username}')
server.broadcast(f'{username} has connected.'.encode("ascii"))
client.send('Connected to the server!'.encode('ascii'))
thread = threading.Thread(target=handle, args=(client,))
thread.start()
except Exception as e:
print(e)
print('Closed early! (Or wrong values entered!)')
socket.close()
print(f'Client {addr} closed.')
client.send()
def listen(self):
self.socket.listen(5)
print('Listening for new connections....')
while True:
client, addr = self.socket.accept()
client.settimeout(60)
server.receive(client, addr)
server = Server(4545)
try:
server.listen()
except:
server.close()

Problem with object oriented comparisons when threading in python

im not too bad at python, and ive tried to make a threaded socket client, but ive hit a problem in my code that i cant solve. Here is the code:
import socket
import threading
class ThreadedServer(object):
def __init__(self, host, port, num):
self.num = num
self.host = host
self.port = port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind((self.host, self.port))
def listen(self):
self.sock.listen(1)
while True:
client, address = self.sock.accept()
client.settimeout(600)
threading.Thread(target = self.listenToClient,args = (client,address)).start()
def listenToClient(self, client, address):
size = 1024
# fix this, please
if self.num == 1:
print("Client 1 connected")
if self.num == 2:
print("Client 2 connected")
if self.num == 3:
print("Client 3 connected")
while True:
data = client.recv(size)
data = data.decode("utf-8")
print("Client", self.num, ": ", data)
# Reply
if data == "lad":
response = "nice"
else:
response = data
client.send(response.encode('utf-8'))
if __name__ == "__main__":
while True:
host = input("Host? ")
port_num = input("Port? ")
try:
port_num = int(port_num)
print("Please connect client")
break
except ValueError:
pass
ThreadedServer(host,port_num, 1).listen()
ThreadedServer(host,port_num, 2).listen()
ThreadedServer(host,port_num, 3).listen()
ThreadedServer.listenToClient()
You see, when i run this, i also connect it to a rather simple client, which sends me data.
In this code, the data i receive is amply called 'data'.
The problem i have in this code is that in the section where i repeat 'if self.num:', i plan for it to give me the following code when i connect 3 client:
Client 1 connected
Client 2 connected
Client 3 connected
but instead it simply repeats 'Client 1 connected' 3 times.
It would be great if anyone could try to solve this problem for me, thanks in advance
Ps: If anyone would like the client too, just ask for it, and i will edit this post to add it in.
You get correct output according to the code you run. Your code has two problems. The first problem is in the main suite. Look at the line ThreadedServer(host,port_num, 1).listen(). It says: create object of class ThreadServer and call method listen() which runs forever (listens to connections forever). You will never start 2 more servers ThreadedServer(host,port_num, 2).listen() and ThreadedServer(host,port_num, 3).listen(). This is good but should be fixed. So you have 1 server which can accept multiple connections. But you count servers instead of clients (this is the second problem which gives you the output you do not expect).
The solution is the following.
Run only 1 server (1 object of class ThreadedServer).
Add counter to the method listen():
def listen(self):
counter = 0
self.sock.listen(1)
while True:
client, address = self.sock.accept()
client.settimeout(600)
counter += 1
threading.Thread(
target=self.listenToClient,
args=(client, address, counter)).start()
Change method listenToClient() a little bit:
def listenToClient(self, client, address, client_id):
size = 1024
print("Client {} connected".format(client_id))
while True:
data = client.recv(size)
data = data.decode("utf-8")
print("Client", self.num, ": ", data)
# Reply
if data == "lad":
response = "nice"
else:
response = data
client.send(response.encode('utf-8'))
And you will get output:
Client 1 connected
Client 2 connected
Client 3 connected

Python Socket - Can't connect a second time

I have set up a socket server with a client and a host.
It works fine until the client has disconnected, with both .shutdown() and .close().
When I then launch the client again, it can't connect.
I presume this is not because of how I've written my code but rather what I haven't written.
How do I make the server truly disconnect the client's connection so that it can connect again?
Server:
import socket, threading, time, json
ONLINE_USERS = []
SESSION = None
class User():
def __init__(user, connection, address):
print('for', address, '{Connection established}')
user.connection = connection
user.address = address
user.character = None
threading.Thread(target=user.process, args=(), daemon=True).start()
def process(user):
time.sleep(1)
user.send("&pLogin\n^^^^^\n")
username = user.send("&iUser>")
password = user.send("&iPass>")
print(user.ping())
print(user.logout())
def send(user, *x):
user.connection.sendall(str.encode(str(x)))
data = user.connection.recv(1024)
return data if data!=b'\x01' else True
def recv(user, x):
user.connection.recv(x)
def ping(user):
start = time.time()
user.connection.sendall(b'\x02')
end = float(user.connection.recv(1024))
return round((end - start) * 1000)
def logout(user):
user.connection.sendall(b'\x04')
return user.connection.recv(4)
class Session():
def __init__(session, host='', port=12345):
session.host = host
session.port = port
session.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
session.socket.bind((host, port))
session.socket.listen(10)
def accept():
conn = User(*session.socket.accept())
session.thread_accept = threading.Thread(target=accept, args=(), daemon=True).start()
def shutdown():
for user in ONLINE_USERS.keys():
ONLINE_USERS[user].connection.sendall(bytes([0xF]))
if __name__ == '__main__':
SESSION = Session()
input('Press heart to continue!\n')
Client:
import socket, sys, threading, time, os
def clear(t=0.5):
time.sleep(t)
os.system('cls')
def tryeval(x, default):
try:
return eval(x)
except:
return default
class Client():
def __init__(client):
try:
server_info = input('IP_ADDRESS:PORT>').split(':')
client.host = server_info[0]
client.port = int(server_info[1])
except:
client.host = 'localhost'
client.port = 12345
client.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.socket.settimeout(10)
try:
client.socket.connect((client.host, client.port))
clear()
client.data_exchange()
finally:
client.shutdown()
def data_exchange(client):
while True:
data = client.socket.recv(1024)
if data:
if data==b'\x02':
client.socket.sendall(str.encode(str(time.time())))
elif data==b'\x04':
client.shutdown()
else:
data = tryeval(data, ())
response = []
for item in data:
try:
prefix, content = item[:2], item[2:]
if prefix=='&p':
print(content, end='')
elif prefix=='&i':
response.append(input(content))
if prefix=='&c':
time.sleep(float(content))
clear()
except:
pass
if len(response)>0:
client.socket.sendall(str.encode(str(tuple(response))))
else:
client.socket.sendall(b'\x01')
time.sleep(0.001)
def shutdown(client):
try:
client.socket.sendall(b'\x04')
except:
pass
print('Shutting down program.')
client.socket.shutdown(socket.SHUT_RDWR)
print('Socket has been shutdown.')
client.socket.close()
print('Socket has been closed.')
print('Exiting program')
time.sleep(1)
sys.exit()
if __name__ == '__main__':
client = Client()
"The server repeatedly calls accept waiting for new incoming connections." No it doesn't. It calls accept once in a thread...which exits. – Mark Tolonen

asyncores's handle_close keeps firing continuously

self.handlers.append(ConnHandler(sock, self.handlers))I'm new to python and I tried to write a simple socket server to test stuff out and get to know the language better.
import asyncore
import socket
import json
class ConnHandler(asyncore.dispatcher_with_send):
def __init__(self, conn, handlerlist):
asyncore.dispatcher_with_send.__init__(self, conn)
self.handlers = handlerlist
def handle_close(self):
self.close()
print 'Socket closed'
if(self.handlers.count(self) > 0):
self.handlers.remove(self);
def handle_read(self):
data = ''
more = True
while more:
try:
data += self.recv(1024)
except socket.error, e:
more = False
if data == '':
return
try:
message = json.loads(data)
except ValueError:
self.send('Invalid JSON\n')
return
print message
class TestServer(asyncore.dispatcher):
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind((host, port))
self.listen(5)
self.handlers = []
def handle_accept(self):
pair = self.accept()
if pair is not None:
sock, addr = pair
print 'Incoming connection from %s' % repr(addr)
self.handlers.append(ConnHandler(sock, self.handlers))
def sendToAll(self, string):
for h in self.handlers:
h.send(string + '\n')
server = TestServer('localhost', 55555)
asyncore.loop()
My problem is the following.
If I connect to the server with telnet and then quit telnet to close the connection, python just spams 'Socket closed' in the terminal. How can I fix this? Are there obvious beginner mistakes in the above code?
handle_close is not meant to detect if peer is disconnected, you get this information in handle_read if .recv call returns an empty string. Then you can close the socket, and then handle_close is called.
Here is a modified version of your code:
def handle_close(self):
print 'Socket closed'
if(self.handlers.count(self) > 0):
self.handlers.remove(self);
def handle_read(self):
data = ''
more = True
while more:
try:
new_data = self.recv(1024)
if not new_data:
self.close()
return
else:
data += new_data
except socket.error, e:
more = False
if data == '':
return
try:
message = json.loads(data)
except ValueError:
self.send('Invalid JSON\n')
return
print message

zeromq: why dealer sends one message and receives from one client?

I'm trying to understand my code's behavior.
I'm using zeromq to create a server that sends a "ping" and waits for "pong" responses.
What i'm seeing is that when I send a ping, only one client receives it.
when I run this code and send "ping" for the first time i receive:
pong: A
and when i run it again, i get
pong: B
why is that? I want to send one "ping" and receive two pongs.
here's the code:
from threading import Thread
import zmq
class zmqdealer(object):
def __init__(self, port):
context = zmq.Context()
self.sock = context.socket(zmq.DEALER)
#self.sock.setsockopt(zmq.RCVTIMEO, 1000)
self.sock.bind("tcp://*:%s" % port)
thread = Thread(target=lambda: self.poll())
thread.daemon = True
thread.start()
def poll(self):
while True:
reply = self.sock.recv()
if reply != "":
print(reply)
def ping(self):
self.sock.send_multipart(['', 'ping'])
class zmqrep(object):
def __init__(self, ident,host, port):
context = zmq.Context()
self.sock = context.socket(zmq.REP)
self.sock.connect("tcp://%s:%s" % (host, port))
self.ident = ident
thread = Thread(target=lambda: self.pong())
thread.daemon = True
thread.start()
def pong(self):
while True:
request = self.sock.recv()
if request == "ping":
msg = "pong: %s" % self.ident
self.sock.send(msg)
if __name__ == "__main__":
port = 11112
host = "localhost"
server = zmqdealer(port)
client1 = zmqrep('A',host,port)
client2 = zmqrep('B',host,port)
answer = raw_input('press <ENTER> to exit or type \'ping\' to get a pong\n')
while True:
if answer == "":
break
if answer == "ping":
server.ping()
answer = raw_input()
EDIT
I found a way to make this work. I really hope there is another way because i genuinely hate this one! so it looks like dealer sends to the clients in a round robin fashion. so to make my ping work i had to send it to all the clients. how? i subscribed to the monitor socket and added every connected client to a list. every time i ping, i ping to every client. look:
import threading
import zmq
from zmq.utils import monitor
def threadify(func, daemon=True):
thread = threading.Thread(target=func)
thread.daemon = daemon
thread.start()
class zmqdealer(object):
def __init__(self, port):
context = zmq.Context()
self.sock = context.socket(zmq.DEALER)
self.monitor_sock = self.sock.get_monitor_socket()
self.sock.bind("tcp://*:%s" % port)
self.connected_clients = {}
threadify(func=self.poll)
threadify(func=self.monitor)
def poll(self):
while True:
reply = self.sock.recv()
if reply != "":
print reply
def add_client(self, event):
endpoint = event['endpoint']
value = event['value']
if endpoint in self.connected_clients:
self.connected_clients[endpoint].append(value)
else:
self.connected_clients[endpoint] = [value]
def remove_client(self, event):
endpoint = event['endpoint']
value = event['value']
if endpoint in self.connected_clients \
and value in self.connected_clients[endpoint]:
self.connected_clients[endpoint].remove(value)
def monitor(self):
options = {zmq.EVENT_ACCEPTED: lambda e: self.add_client(e),
zmq.EVENT_DISCONNECTED: lambda e: self.remove_client(e)}
while True:
event = monitor.recv_monitor_message(self.monitor_sock)
event_type = event['event']
if event_type in options:
options[event_type](event)
event['event'] = event_types[event_type]
print event
def ping(self):
connected_clients_amount = sum([len(clients) for clients in self.connected_clients.values()])
for i in xrange(connected_clients_amount):
self.sock.send_multipart(['', 'ping'])
if connected_clients_amount <= 0:
print "there are no connected clients!"
class zmqrep(object):
def __init__(self, ident, host, port):
context = zmq.Context()
self.sock = context.socket(zmq.REP)
self.sock.connect("tcp://%s:%s" % (host, port))
self.identity = ident
self.stopped = threading.Event()
threadify(self.pong)
def pong(self):
while not self.stopped.isSet():
request = self.sock.recv()
if request == "ping":
msg = "pong: %s" % self.identity
self.sock.send(msg)
self.sock.close()
def stop(self):
self.stopped.set()
if __name__ == "__main__":
port = 11112
host = "localhost"
num = 5
server = zmqdealer(port)
clients = [zmqrep(i.__str__(), host, port) for i in xrange(num)]
answer = raw_input('press <ENTER> to exit or type \'ping\' to get a pong\n')
while True:
if answer == "":
break
if answer == "ping":
server.ping()
if answer == "kill":
if len(clients) > 0:
die = clients[0]
clients.remove(die)
die.stop()
else:
print "there are no connected clients!\n"
answer = raw_input()
Router/Dealer sockets are best used for distributing tasks. Say you have 10 tasks and 2 workers, you do not care who does what. Dealer/Router will distribute in a round robin fashion.
Maybe Pub/Sub or Push/Pull sockets would fit your usecase better? They are both broadcast sockets.
Here's an example of Push/Pull used in a similar fashion as what you're doing.
You often end up doing pairs of sockets, one to transmit and one other to receive results. You could for example do a PUSH with a ping message + random identifier, and ask clients to answer on PUB/SUB where you subscribe to this random identifier. This way you can match requests and responses.

Categories