Как сохранить сокет открытым до тех пор, пока клиент не закроет его?

156
17

У меня есть простой сервер и клиент python.


Сервер:


import SocketServer
import threading

class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024).strip()
print str(self.client_address[0]) + " wrote: "
print self.data
self.request.send(self.data.upper())

if __name__ == "__main__":
HOST, PORT = "localhost", 3288
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()


Клиент:


import socket
import sys
from time import sleep

HOST, PORT = "localhost", 3288
data = "hello"

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
sock.connect((HOST, PORT))
sock.send(data + "\n")
received = sock.recv(1024)

sleep(10)

sock.send(data + "\n")
received = sock.recv(1024)

sleep(10)

sock.send(data + "\n")
received = sock.recv(1024)

finally:
sock.close()


Вот результат, который я получаю:


Сервер:


>python server.py
127.0.0.1 wrote:
hello

Клиент:


>python client.py
Traceback (most recent call last):
File "client.py", line 18, in <module>
received = sock.recv(1024)
socket.error: [Errno 10053] An established connection was aborted by the software in your host machine

Я попробовал это и на Linux-машине. Сервер получает только одно сообщение, а затем я получаю сообщение об ошибке второго сообщения. Я только начал изучать сети на python, но я думаю, что по какой-то причине сервер закрывает сокет. Как это исправить?

спросил(а) 2021-01-19T18:28:55+03:00 2 месяца, 3 недели назад
1
Решение
193

Объект A MyTcpHandler создается для каждого соединения, а handle вызывается для работы с клиентом. Соединение закрывается, когда возвращается handle, поэтому вам необходимо обработать полное сообщение от клиента в методе handle:


class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
while 1:
self.data = self.request.recv(1024)
if not self.data:
break
self.data = self.data.strip()
print str(self.client_address[0]) + " wrote: "
print self.data
self.request.send(self.data.upper())

ПРИМЕЧАНИЕ: recv возвращает '', когда клиент закрывает соединение, поэтому я переместил .strip() после recv, поэтому нет ложного сигнала из-за того, что клиент отправляет только пустое пространство.

ответил(а) 2021-01-19T18:28:55+03:00 2 месяца, 3 недели назад
61

Сначала я признаю, что прошло много лет с тех пор, как я в последний раз использовал SocketServer, поэтому могут быть более идиоматические подходы к решению вашей проблемы.


Обратите внимание, что ваш клиент открывает одно соединение и отправляет три набора данных и получает три набора данных. (Надеемся, что стек TCP отправит буферизованные данные после вызова receive() в сокете.)

Ожидается, что ваш сервер будет обрабатывать клиентское соединение полностью, от начала до конца, когда он вызывается из механизма обратного вызова SocketServer. Ваш текущий класс делает немного ввода-вывода, а затем завершает работу. Вам просто нужно расширить обратный вызов сервера, чтобы сделать больше:


class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024).strip()
print str(self.client_address[0]) + " wrote: "
print self.data
self.request.send(self.data.upper())
foo = self.request.recv(1024).strip()
self.request.send(foo.lower())
bar = self.request.recv(1024).strip()
self.request.send("goodbye " + bar)

ответил(а) 2021-01-19T18:28:55+03:00 2 месяца, 3 недели назад
62

К аналогичной проблеме здесь Ошибка: [Errno 10053]


Я тоже пробовал то же самое и получил ту же ошибку.


Если для демонстрации этой ошибки существует такой простой код:


import socket 

host = 'localhost'
port = 5001
size = 102400
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
for msg in ['Hello, world','Test','anything goes here']:
s.send(msg)
data = s.recv(size)
print 'Received:', data
s.close()


Если вы создаете объект сокета и amt, который он может отправлять и эхо от сервера, чтобы узнать, сколько его получателей, если вы его изменяете, скажем 1024 - 102400 (в этом коде);
Это означает, что сокет не должен закрываться, но снова в моей ОС Windows, серверная сторона продолжает прослушивать и печатать любые данные, которые отправляет клиент, но на стороне клиента вы получаете эту ошибку;


Однако, если клиент может подключиться только один раз и отправлять и получать только один раз, то именно так он был разработан. Попытка этого работает без ошибок:


for msg in ['Hello, world','Test','anything goes here']:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
s.send(msg)
data = s.recv(size)
s.close()
print 'Received:', data

Я не уверен, что один объект сокета работает только один раз для отправки и получения данных.


UPDATE
Я думаю, что проблема заключалась в способности каждого клиентского сокета получать данные в соответствии с установленным буферизацией;
Вот почему второй фрагмент кода выше работает, создавая новые сокеты для подключения клиентов на сервере. Но в этом случае многие сокеты будут израсходованы.


Вместо этого следующий код исправил эту проблему, проверив размер используемого размера. Если он превышает заданную сумму, он создает новый сокет на клиентах, но обеспечивает отправку сообщения; На самом деле проблема была связана с кодом сервера, но исправила его.


size = 10


Это быстрая попытка ребенка в коде. Я уверен, что вы поймете и оптимизируете его к лучшему!


клиентский код:


messag = ['Hello, world', 'Test', 'anything goes here']

def client_to_server(messag,host,port,size):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
countmsg = 0
restmsg = ''
for msg in messag:
strl = tmsg = msg
if len(restmsg):
tmsg = restmsg + ' ' + msg
countmsg = len(tmsg)
if countmsg <= size:
pass
else:
restmsg = tmsg[size:]
tmsg = tmsg[:size]
#s.close()
countmsg = len(tmsg)
#s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#s.connect((host, port))
print 'Sending to server msg {}'.format(tmsg)
s.send(tmsg)
# s.settimeout(1)
try:
data = s.recv(size)
print 'Received:', data
if strl == data:
print strl,data
countmsg = 0
restmsg = ''
except (socket.error), e:
print e.args,e.message
s.close()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.close()
if restmsg:
client_to_server([restmsg],host,port,size)
return

client_to_server(messag,host,port,size)


Код сервера:


size = 1024  #This has to be bigger than client buf size!
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
s.listen(backlog)
while True:
#this is what accepts and creates a P2P dedicated client socket per socket
client, address = s.accept()
try:
data = client.recv(size)
while data or 0:
print "Client sent {} | Server sending data to client address {}".format(data, address)
client.send(data)
data = client.recv(size)
else: client.close()
except (socket.error), e:
client.close()
print e.args, e.message

Попробуйте. Это использует тот же сокет.

ответил(а) 2021-01-19T18:28:55+03:00 2 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема