#python #sockets
#python #сокеты
Вопрос:
Итак, у меня есть следующий фрагмент кода, выполняемый в отдельном потоке:
#Starts listening at the defined port on a separate thread. Terminates when 'stop' is received.
def start(self):
try:
if not self.is_running:
self.is_running = True
while self.is_running:
self.socket.listen(1)
conn, addr = self.socket.accept()
#Messages are split with $ symbol to indicate end of command in the stream.
jStrs = [jStr for jStr in conn.recv(self.buffer_size).decode().split('$') if jStr != '']
DoSomethingWith(jStrs)
except Exception as ex:
raise SystemExit(f"Server raised error: {ex}")
В части отправителя у меня есть что-то вроде этого:
#Sends a string message to the desired socket.
#@param message: The string message to send.
def send(self, message):
if not self.connected:
self.connect()
self.socket.send(message.encode())
#self.close()
#self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
То, что я отправляю через сокет и как я его использую, не имеет отношения к проблеме, поэтому я оставил это для ясности. Когда я использую свой метод отправки в первый раз, все в порядке и работает так, как задумано. Отладчик выполняет всю процедуру While и останавливается на self.socket.accept() . Когда я делаю ту же отправку после say time.sleep(2), ничего не происходит. Мой метод отправки не блокируется, хотя я проверил.
Обратите внимание на закомментированные строки в отправителе. Когда я закрываю соединение и создаю новый сокет после каждой отправки, у меня нет этой проблемы, но почему?
Когда я делаю обе отправки сразу один за другим без какого-либо промежутка времени между ними, оба будут поступать одновременно, что является ожидаемым поведением. Почему мой self.socket.accept() никогда не вызывается во второй раз, если между двумя вызовами есть промежуток времени (даже такой маленький, как время, необходимое для печати чего-либо)?
Комментарии:
1. Работает по определению. Вам нужно создать цикл с
conn.recv
вызовами — получать все от принятого клиента, пока сокет не будет закрыт.2. Переместите прослушивание за пределы цикла. Создайте клиентский сокет, прежде чем пытаться что-либо отправить. Странный код.
3. Второй код — это просто метод более крупного класса, который создает сокет и все остальное. Я опустил все эти фрагменты кода для ясности, потому что думал, что люди будут считать, что сокет создан, поскольку я использую self .
Ответ №1:
Создайте свой объект сокета один раз, затем отправьте по нему сообщения.
sender = socket.socket()
def send(sender, message):
if not sender.connected:
sender.connect()
sender.send(message.encode())
При необходимости вы можете обернуть это в класс с инициализацией.
https://pythontic.com/modules/socket/introduction
Комментарии:
1. Это не видно из фрагмента кода, который я представил, но сокет-отправитель уже создан внутри класса один раз при создании. Я всегда использую один и тот же сокет в примере
2. хорошо. Увидел, что одна строка закомментирована, и упомянул, что, возможно, каждый раз создает новую. Думал, что вы боретесь с этим.
Ответ №2:
Мне удалось устранить проблему благодаря @Alex F из комментариев. Кажется, я выполнил цикл не в том месте. Вы не хотите зацикливать self.socket.accept(), но часть conn.recv() после принятия сокета. Простое перемещение цикла while ниже self.socket.accept() сработало для меня.
#Starts listening at the defined port on a separate thread. Terminates when 'stop' is received.
def start(self):
try:
if not self.is_running:
self.is_running = True
self.socket.listen(1)
#<---- moved from here
conn, addr = self.socket.accept()
while self.is_running: #<---- to here
#Messages are split with $ symbol to indicate end of command in the stream.
jStrs = [jStr for jStr in conn.recv(self.buffer_size).decode().split('$') if jStr != '']
#Loads the arguments and passes them to the remotes dictionary
#which holds all the methods
for jStr in jStrs:
jObj = json.loads(jStr)
func_name = jObj["name"]
del jObj["name"]
remote.all[func_name](**jObj)
except Exception as ex:
raise SystemExit(f"Server raised error: {ex}")