2011-12-25 8 views
12

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

+0

это может помочь: http://stackoverflow.com/a/20421867/2290820 – user2290820

ответ

20

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

+0

Спасибо за ответ – Bruce

1

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

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

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

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) 
+0

Спасибо за ответ – Bruce

1

К подобной проблемой здесь error: [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() 

Если вы создаете объект сокета и АМТ он может отправлять и эхо обратно от сервера, чтобы увидеть, насколько это приемники, если вы варьируются, например, 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 

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

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

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

размер = 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 

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