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

У меня есть простой сервер и клиент 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, но я думаю, что по какой-то причине сервер закрывает сокет. Как это исправить?

Ответы

Ответ 1

Объект 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, поэтому нет ложного сигнала из-за того, что клиент отправляет только пустое пространство.

Ответ 2

Сначала я признаю, что прошло много лет с тех пор, как я в последний раз использовал 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)

Ответ 3

К аналогичной проблеме здесь Ошибка: [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

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