Это происходит, когда сообщение, передаваемое серверу другим клиентам, превышает длину имени пользователя. У кого-нибудь есть починка? Пожалуйста, смотрите мой код ниже как для сервера чата, так и для клиента. Я считаю, что ошибка вызвана строкой 28 или 34 клиентского кода, но я не знаю, как ее исправить. Любая помощь будет принята с благодарностью!
Код сервера:
import socket
import select
host = '127.0.0.1'
port = 65432
HEADER_LENGTH = 100
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Creating socket object
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # Allowing the same address to be reused
s.bind((host, port)) # Binding the socket to the IP address and port number
s.listen() # Listening for incoming connections
print(f'Listening for incoming connections on IP address {host}.')
client_socket_list = [s] # List for appending connected sockets to for select to keep track of
clients = {} # Dict for informing other clients in a better way than just socket info who they are
# Defining a function for receiving messages from client sockets
def receiving_messages(client_socket):
try:
msg_header = client_socket.recv(HEADER_LENGTH) # Getting the message header
# If we do not get any data for the message header then we need code to handle this
if not len(msg_header):
return False
else:
msg_length = int(msg_header.decode("utf-8")) # Converting the header to a length
return {"header": msg_header, "data": client_socket.recv(msg_length)} # Returning the data from the message
except:
return False
while True:
# Below socket is taking in parameters (1, 2, 3) (1) the read list(things we want to read in)(2) the sockets we want to write (3) sockets with possible error
read_sockets, _, exception_sockets = select.select(client_socket_list, [], client_socket_list)
for x in read_sockets: # x = socket that has been notified of chat room entry (iterating over sockets with info to be read)
if x == s: # Handling for a new connection
client_socket, client_address = s.accept() # Accepting a new connection, getting unique client socket and address
user = receiving_messages(client_socket) # User data
if user is False: # Handling for a disconnection
continue
client_socket_list.append(client_socket) # Adding the new client socket to the list
clients[client_socket] = user # Adding the user information to the clients dictionary
print(f"New connection accepted from IP: {client_address[0]} Port: {client_address[1]} username: {user['data'].decode('utf-8')}")
else:
message = receiving_messages(x) # If the socket is not the server socket then we have a message to read
if message is False:
print(f"Connection closed from {clients[x]['data'].decode('utf-8')}")
client_socket_list.remove(x) # Removing the socket on which the connection has been closed from the list of clients
del clients[x] # Removing the client info from the dict
continue
user = clients[x]
print(f"Received message from {user['data'].decode('utf-8')}: {message['data'].decode('utf-8')}")
# Now sharing the message with all other users in the chatroom
for client_socket in clients: # Iterating over all connecting clients
if client_socket != x: # Stopping the message being sent out to the client that sent the message
client_socket.send(user['header'] + user['data'] + message['header'] + message ['data']) # Sending the message from client X to all other clients
# Removing users if there is a socket error causing unexpected connection closure
for x in exception_sockets:
client_socket_list.remove(x)
del clients[x]
Код клиента:
import socket
import errno
import sys
HEADER_LENGTH = 100
host = '127.0.0.1'
port = 65432
my_username = input('Username: ') # User input of username (Not encoded in utf-8 bytes)
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((host, port))
client_socket.setblocking(False) # Telling the recv method not to block
# Server expects the first message to be a username input by the user
username = my_username.encode('utf-8') # Encoding the user into bytes to send
username_header = f'{len(username):<{HEADER_LENGTH}}'.encode('utf-8') # Defining a variable username_header and stating that the length of the username must be aligned to the left within the specified length set by HEADER_LENGTH
client_socket.send(username_header + username) # Sending client username info to the server
# Sending messages
while True:
message = input(f'{my_username} : ') # my_username used so it is not already encoded when using it here to attach the message the user inputs
# Sending messages and handling for an empty input i.e. no message input
if message:
message = message.encode('utf-8') # Encoding the message into utf-8 bytes ready to send to the server
""" line 28 """message_header = f'{len(message):<{HEADER_LENGTH}}'.encode('utf-8') # Defining a variable message_header containing the information that the length of the message must be aligned to the left within the length of the username header
client_socket.send(message_header + message) # Encoded message now sent along with the message length info
try:
while True:
# Receiving messages from other clients
""" line 34 """username_header = client_socket.recv(HEADER_LENGTH)
if not len(username_header): # Handling for an error where the username header length is not what it should be
print('connection closed by the server')
sys.exit() # System closing the connection due to no more messages
# Getting the username of the other client that sent the last message
username_length = int(username_header.decode('utf-8').strip()) # Possibly username length
username = client_socket.recv(username_length).decode('utf-8')
# Getting the message from the server that the other client has sent
message_header = client_socket.recv(HEADER_LENGTH)
message_length = int(message_header.decode('utf-8').strip())
message = client_socket.recv(username_length).decode('utf-8')
print(f'{username}: {message}') # Printing the message from the other client along with that clients username
# Preventing consistent errors being raised causing issue within the program as within a non- blocking connection an error will continually be raised when no messages are coming through etc
except IOError as e:
if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK and e.errno != errno.WASEWOULDBLOCK:
print('Expecting message but not receiving ', str(e))
sys.exit()
continue
# Handling for all other unexpected errors that may occur
except Exception as e:
print('General error ', str(e))
sys.exit()