У меня проблема с клиентом и сервером Python socket - мне нужен следующий обмен:
- Клиент отправляет сообщение на сервер.
- Сервер читает сообщение и делаетоснованное на нем решение.
- Сервер отправляет соответствующее сообщение клиенту.
Я застреваю в последнем пункте.Что бы я ни пытался, клиент не получит сообщение, отправленное сервером.Обратитесь к приведенному ниже коду:
Клиент:
import socket, select
ip = ["10.189.165.14", 25565]
# Client class to manage server connections
class Client:
def __init__(self, ip:list):
self.sock = socket.socket() # Create the socket object
ip[1] = int(ip[1]) # Convert the port number provided into an int
self.ip = tuple(ip) # Save the inputted IP and port (sock.connect requires a tuple, so convert it here)
def connect(self):
"""Method to attempt to connect to the server"""
self.sock.settimeout(3) # Set the timeout period that the client will try to connect for
self.sock.connect(self.ip) # Connection to the host and port
self.conn = self.sock # Set self.conn = self.sock, for consistent variable naming with the server code
self.sock.setblocking(False) # Set socket to be non-blocking so it errors with BlockingIOError instead of blocking the connection
print("This is the CLIENT; Connected to server")
return True # Return True to the caller so it knows a successful connection has been established
def recv_info(self):
"""Method to receive information from the server in an x byte string"""
for _ in range(100): # Run this method multiple times, until the incoming variable receives information
incoming, _, _ = select.select([self.conn], [], [], 0.01) # Monitor incoming messages from the socket
if incoming: # If there is an incoming message from the server
dataRecv = []
while True: # Infinite loop to break the received bytes data into chunks and load them individually
packet = b"" # Reset packet to a blank byte string
try:
packet = self.conn.recv(4096) # Receive data from server into packet
except BlockingIOError: # If packet gets nothing from the recv()
break # Break out of this while loop
if not packet:
break # If the packet has received nothing from the connection, break this loop
dataRecv.append(packet) # Add the packet onto dataRecv
return dataRecv # Return the received message
client = Client(ip) # Create the client object
conn = client.connect() # Establish a connection with the server
if conn == True: # If connection is successful
client.conn.sendall(b"Send to server") # Send message to the server
print("Sent to server")
recv = client.recv_info() # Look for message from the server
print(f"Received {recv} from server")
Сервер:
import socket, select
class Server:
def __init__(self):
self.sock = socket.socket() # Create the socket object upon instantiation
self.ip = (socket.gethostbyname(socket.gethostname()), 25565) # Make machine name, socket and port visible to the outside world
self.sock.bind(self.ip) # Bind the IP and port to the socket
def connect(self):
"""Method to connect to a client socket"""
self.sock.settimeout(5) # Set the timeout period that the server will wait for a connection
self.sock.listen(5) # Number of allowed unaccepted connections before refusing new connections (i.e. connection queue length)
try:
self.conn, addr = self.sock.accept() # Wait to establish connection with an outside client
except socket.timeout: # If the timeout period elapses without a connection
return False # Exit this method
print("This is the SERVER; Connected to client")
self.sock.setblocking(False) # Set socket to be non-blocking so it errors with BlockingIOError instead of blocking the connection
return True # Return True so the caller knows that a connection has been established
def recv_info(self):
"""Method to receive information from the client in an x byte string"""
for _ in range(100): # Run this method multiple times, until the incoming variable receives information
incoming, _, _ = select.select([self.conn], [], [], 0.01) # Monitor incoming messages from the socket
if incoming: # If there is an incoming message from the client
dataRecv = [] # Start dataRecv as an empty list for this _ iteration
while True: # Infinite loop while receiving data
packet = b"" # Reset packet to a blank byte string
try:
packet = self.conn.recv(4096) # Receive data from client into packet
except BlockingIOError: # If self.conn.recv() is blocked
break # Break out of this while loop
if not packet: # If packet gets nothing from the recv()
break # Break out of this while loop
dataRecv.append(packet) # Add the packet onto dataRecv
# self.conn.sendall(b"Send to client")
print(f"Received {dataRecv} from client")
# Decision making logic to decide on what msg should be
msg = b"Send to client"
self.conn.sendall(msg)
print("Sent to client")
break # Break out of the outer incoming attempts loop
server = Server() # Initialise the server
serverRunning = True
while serverRunning == True: # This boolean always starts as True
conn = server.connect() # Check for a client connection; will return True or False
if conn == True:
# When a connection is established, receive information from the client
server.recv_info() # recv_info() contains an infinite loop to receive information
Запуск этого дает вывод:
Клиент:
Это КЛИЕНТ;Подключено к серверу
Отправлено на сервер
Получено Нет от сервера
Сервер:
Это СЕРВЕР;Подключено к клиенту
Отправлено клиенту
Получено [b'Send to server '] от клиента
Что не работает, так как клиент ничего не получил.
Если вы раскомментируете строку
self.conn.sendall(b"Send to client")
в Server.recv_info (), то внезапно это сработает.Но мне нужно держать sendall вне цикла while True, я думаю, если входящее сообщение разделено на несколько пакетов?Я не уверен, почему это будет работать, когда sendall вне цикла не работает.
Я думаю, что в сокетах должно быть что-то, чего я не понимаю.Я поиграл с блокировкой / неблокировкой, закрытием соединения с сокетом, добавлением времени ожидания и прочел много вопросов здесь (самый близкий, что я нашел, это У меня проблемы с тем, чтобы заставить сервер сокетов Python получать командыиз клиента сокета Python ), но безрезультатно.Любые идеи будут приветствоваться.