Reputation: 35
So i'm also including the server side of the code, but the issues in the client side. It's a simple TCP client socket code.The thing is that in line 21, after the first while loop (i've also commented in the code to where i'm referring to), i'm asking for user input.
What then happens is that when more user connects, the chat screen of any user doesn't gets updated unless they press enter, as you can see, it only continues after an input is given to the 'message' variable.
Now i do know that threading need to be done in here, but i've not really got enough knowledge related to that. So if someone could kindly guide me or help me modify the code so that the chat gets updated without the need to enter.
Cient Code (Issue in line 21, after first while loop...commented)
from socket import *
import select
import errno
import sys
header_length = 10
ip = "127.0.0.1"
port = 1234
my_username = input("Username: ")
client_socket = socket(AF_INET, SOCK_STREAM)
client_socket.connect((ip, port))
client_socket.setblocking(False)
username = my_username.encode()
username_header = f"{len(username):<{header_length}}".encode()
client_socket.send(username_header + username)
while True:
#Where my issue is
message = input(f"{my_username} > ")
if message:
message = message.encode()
message_header = f"{len(message):<{header_length}}".encode()
client_socket.send(message_header + message)
try:
while True:
#receive messages
username_header = client_socket.recv(header_length)
if not len(username_header):
print("Connection closed by the server...")
sys.exit()
username_length = int(username_header.decode().strip())
username = client_socket.recv(username_length).decode()
message_header = client_socket.recv(header_length)
message_length = int(message_header.decode().strip())
message = client_socket.recv(message_length).decode()
print(f"{username} > {message}")
except IOError as e:
if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
print("Reading error: ", str(e))
sys.exit()
continue
except Exception as e:
print("General error: ", str(e))
sys.exit()
Server Code (Just if someone need):
from socket import *
import select
header_length = 10
ip = "127.0.0.1"
port = 1234
server_socket = socket(AF_INET, SOCK_STREAM)
server_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
server_socket.bind((ip, port))
server_socket.listen()
socket_list = [server_socket]
clients = {}
#Handles message receiving
def recieve_message(client_socket):
try:
message_header = client_socket.recv(header_length)
if not len(message_header):
return False
message_length = int(message_header.decode().strip())
return {'header': message_header, 'data': client_socket.recv(message_length)}
except:
return False
print(f'Listening for connections on {ip}:{port}...')
while True:
read_sockets, _, exception_sockets = select.select(socket_list, [], socket_list)
for notified_socket in read_sockets:
if notified_socket == server_socket:
client_socket, client_address = server_socket.accept()
user = recieve_message(client_socket)
if user is False:
continue
socket_list.append(client_socket)
clients[client_socket] = user
print(f"Accepted new connection from {client_address[0]}:{client_address[1]} username:{user['data'].decode()}")
else:
message = recieve_message(notified_socket)
if message is False:
print(f"Closed connection from {clients[notified_socket]['data'].decode()}")
socket_list.remove(notified_socket)
del clients[notified_socket]
continue
user = clients[notified_socket]
print(f"Recieved messasge from {user['data'].decode()}: {message['data'].decode()}")
for client_socket in clients:
if client_socket != notified_socket:
client_socket.send(user['header'] + user['data'] + message['header'] + message['data'])
for notified_socket in exception_sockets:
socket_list.remove(notified_socket)
del clients[notified_socket]
I've also included the image...as you can see as i typed hello in cliend 1's window, client 2's doesnt show it. And it will not until i input something and press enter
Thanks a lot :)
Upvotes: 0
Views: 104
Reputation: 32073
Why do you not use select.select
for the client as you do for the server?
It works perfectly.
Linux version
from socket import *
import select
import errno
import sys
def prompt(username):
sys.stdout.write(f"{username} > ")
sys.stdout.flush()
header_length = 10
ip = "127.0.0.1"
port = 1234
my_username = input("Username: ")
client_socket = socket(AF_INET, SOCK_STREAM)
client_socket.connect((ip, port))
client_socket.setblocking(False)
username = my_username.encode()
username_header = f"{len(username):<{header_length}}".encode()
client_socket.send(username_header + username)
while True:
socket_list = [sys.stdin, client_socket]
prompt(my_username)
read_sockets, write_sockets, error_sockets = select.select(socket_list, [], [])
for socket in read_sockets:
try:
if socket == sys.stdin:
message = sys.stdin.readline()
message = message.encode()
message_header = f"{len(message):<{header_length}}".encode()
client_socket.send(message_header + message)
elif socket == client_socket:
username_header = client_socket.recv(header_length)
if not len(username_header):
print("Connection closed by the server...")
sys.exit()
username_length = int(username_header.decode().strip())
username = client_socket.recv(username_length).decode()
message_header = client_socket.recv(header_length)
message_length = int(message_header.decode().strip())
message = client_socket.recv(message_length).decode()
print(f"\n{username} > {message}")
except IOError as e:
if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
print("Reading error: ", str(e))
sys.exit()
continue
except Exception as e:
print("General error: ", str(e))
sys.exit()
Windows/Linux version (because of select
restriction)
Note: File objects on Windows are not acceptable, but sockets are. On Windows, the underlying select() function is provided by the WinSock library, and does not handle file descriptors that don’t originate from WinSock.
import threading
from socket import *
import select
import errno
import sys
def prompt(username):
sys.stdout.write(f"{username} > ")
sys.stdout.flush()
def redirect_sdtin(dest):
for ln in sys.stdin:
dest.send(ln.encode())
header_length = 10
ip = "127.0.0.1"
port = 1234
my_username = input("Username: ")
stdin_in, stdin_out = socketpair()
threading.Thread(target=redirect_sdtin, args=(stdin_in,), daemon=True).start()
client_socket = socket(AF_INET, SOCK_STREAM)
client_socket.connect((ip, port))
client_socket.setblocking(False)
username = my_username.encode()
username_header = f"{len(username):<{header_length}}".encode()
client_socket.send(username_header + username)
while True:
socket_list = [stdin_out, client_socket]
prompt(my_username)
read_sockets, write_sockets, error_sockets = select.select(socket_list, [], [])
for socket in read_sockets:
try:
if socket == stdin_out:
message = stdin_out.recv(1024)
message_header = f"{len(message):<{header_length}}".encode()
client_socket.send(message_header + message)
elif socket == client_socket:
username_header = client_socket.recv(header_length)
if not len(username_header):
print("Connection closed by the server...")
sys.exit()
username_length = int(username_header.decode().strip())
username = client_socket.recv(username_length).decode()
message_header = client_socket.recv(header_length)
message_length = int(message_header.decode().strip())
message = client_socket.recv(message_length).decode()
print(f"\n{username} > {message}")
except IOError as e:
if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
print("Reading error: ", str(e))
sys.exit()
continue
except Exception as e:
print("General error: ", str(e))
sys.exit()
Upvotes: 1