I am trying to make a basic terminal-based chat application with python. I used select() to update readable/writable connections. After two messages from each client however, the server returns an empty readable list (sockets_list).
I already tried removing code that deletes connections from my sockets list.
this is server.py
import socket
import select
import time
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# host, port
host = 'localhost'
port = 5555
# bind and listen for connections
sock.bind((host, port))
sock.listen(2)
print('Server started on. {} {}'.format(host, port))
# select lists
sockets_list = [sock]
outputs = []
clients = {}
def receive_message(conn):
try:
msg = conn.recv(4096)
if not len(msg):
return False
return msg
except conn.error as e:
return False
while True:
print('\n waiting for the next event')
readable, writable, exceptions = select.select(sockets_list, outputs, [], 10)
print(readable, writable)
for s in readable:
if s == sock:
connection, address = s.accept()
user = receive_message(connection)
if user is False:
continue
sockets_list.append(connection)
clients[connection] = user
print(f'Accepted new connection from {user.decode()}')
else:
arr = s.recv(4096).decode().split(':')
if len(arr) < 2:
arr = s.recv(4096).decode().split(':')
elif len(arr) >= 2:
message = arr[1]
# if message is False:
# print(f'Connection closed with {s}')
#
# sockets_list.remove(s)
# del clients[s]
#
# continue
user = clients[s]
print(f'Received message from {user.decode()}: {message}')
for client in clients:
# But don't sent it to sender
if client != s:
# Send user and message (both with their headers)
# client.send(user['header'] + user['data'] + message['header'] + message['data'])
client.send(f"{user.decode()}:{message}".encode())
print(f'Sending {message} to {clients[client].decode()}')
This is client.py:
import socket
import select
import errno
import sys
IP = "localhost"
PORT = 5555
current_user = input("Username: ")
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((IP, PORT))
# client.setblocking(False)
username = current_user.encode()
client.send(username)
while True:
message = input(f'{current_user} > ')
if message:
# Encode message to bytes, prepare header and convert to bytes, like for username above, then send
client.send(f'{current_user}:{message}'.encode())
try:
while True:
arr = client.recv(4096).decode().split(':')
username = arr[0]
if not username:
print('Connection closed by the server')
sys.exit()
message = arr[1]
# Print message
print(f'{username} > {message}')
message = input(f'{current_user} > ')
except IOError as e:
print(e)
sys.exit()
except Exception as e:
print(e)
I expect the server to receive/send messages from both clients. Meaning whatever client 1 sent, client 2 will see.
The issue was that I wasn't sending/receiving the data properly with the client. So I tweaked it a little bit and it works now!
while True:
message = input(f'{current_user} > ')
if message:
client.send(f'{current_user}:{message}'.encode())
arr = client.recv(4096).decode().split(':')
if arr:
username = arr[0]
message = arr[1]
# Print message
print(f'{username} > {message}')
Putting a forever loop in a forever loop didn't make sense so I got rid of it.
I checked if the client received data with if arr:
and printed the data. Since arr was in the forever loop, it ALWAYS checked for data.
To send data, it was pretty simple, get input, send it via socket.