2011-12-25 10 views
12

Tengo servidor y cliente python simples.¿Cómo mantener un socket abierto hasta que el cliente lo cierra?

Servidor:

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() 

Cliente:

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() 

Aquí está la salida me sale:

Servidor:

>python server.py 
127.0.0.1 wrote: 
hello 

Cliente:

>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 

Lo probé en una máquina Linux también. El servidor solo recibe un mensaje y luego aparece un error en la declaración recv del segundo mensaje. Acabo de empezar a aprender a trabajar en red en Python, pero creo que el servidor está cerrando el socket por alguna razón. ¿Cómo puedo corregir esto?

+0

esto podría ayudar: http://stackoverflow.com/a/20421867/2290820 – user2290820

Respuesta

20

Un objeto MyTcpHandler para cada conexión, y handle está llamado a tratar con el cliente. La conexión se cierra cuando handle devoluciones, así que hay que manejar la comunicación completa del cliente dentro del handle método:

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()) 

NOTA: recv vuelve '' cuando el cliente cierra la conexión, por lo que se trasladaron .strip() después de la recv por lo que no hay una falsa alarma debido a que el cliente solo envía espacio en blanco.

+0

Gracias por la respuesta – Bruce

1

Primero admitiré que han pasado años desde la última vez que utilicé SocketServer, por lo que podría haber más enfoques idiomáticos para resolver su problema.

Tenga en cuenta que su cliente abre una única conexión y envía tres conjuntos de datos y recibe tres conjuntos de datos. (Esperemos que la pila TCP enviar datos almacenados una vez que se llama a en el zócalo.)

Su servidor está a la espera para manejar una conexión de cliente completo, de principio a fin, cuando se le llama desde el mecanismo SocketServer de devolución de llamada. Su clase actual hace un poco de IO y luego sale de. Sólo tiene que extender su devolución de llamada del servidor para hacer más: se crea

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

Gracias por la respuesta – Bruce

1

a un problema similar aquí error: [Errno 10053]

también intentaron lo mismo y tiene el mismo error.

Si hay un código simple como esto para demostrar este error:

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() 

Si crea un objeto de socket y el AMT se puede enviar y echo hacia atrás desde el servidor al ver la cantidad de receptores que, si varíe eso, digamos 1024 a 102400 (en este código); Lo que significa que el socket no se debe cerrar, pero de nuevo en mi sistema operativo Windows, el lado del servidor sigue escuchando e imprimiendo cualquier información que el cliente envíe, pero en el lado del cliente se obtiene este error;

Sin embargo, si es que el cliente puede conectarse solo una vez y enviar y recibir solo una vez, entonces así fue como fue diseñado. Tratar esto funciona sin errores:

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 

No estoy seguro de si un objeto socket funciona sólo una vez para enviar y recibir datos.

ACTUALIZACIÓN Creo que el problema era la capacidad por socket del cliente para recibir datos de acuerdo con el buffersize fijo; Es por eso que el segundo fragmento de código anterior funciona creando así nuevas conexiones de conexión de cliente en el servidor. Pero de esa manera, muchos enchufes se van a agotar.

En su lugar, el siguiente código solucionó ese problema al verificar la cantidad de tamaño que se estaba utilizando. Si excede la cantidad dada, crea un nuevo socket en los clientes pero se asegura de que el mensaje sea enviado; En realidad, el problema fue con el código del servidor, pero lo solucionó.

size = 10

Se trata de un intento de bebé rápido en el código. ¡Estoy seguro de que lo entenderías y lo optimizarías para mejor!

código de cliente:

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) 

código del servidor:

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 

probarlo. Esto usa el mismo socket.

Cuestiones relacionadas