2009-09-24 14 views
12

Me estoy enseñando la creación de redes de Python, y recordé que cuando me enseñaba a enhebrar me encontré con this page, así que copié las secuencias de comandos, las actualicé para Python 3.1.1 y las ejecuté. Funcionaron perfectamente¿Por qué el host aborta la conexión?

Luego hice algunas modificaciones. Mi objetivo es hacer algo simple:

  1. El cliente crea un número entero y lo envía al servidor.
  2. El servidor recibe el número entero encurtido, lo deshace, lo dobla, lo guarda en salmuera y lo envía de vuelta al cliente.
  3. El cliente recibe el entero en escabeche (y duplicado), lo deshace y lo emite.

Aquí está el servidor:

import pickle 
import socket 
import threading 

class ClientThread(threading.Thread): 
    def __init__(self, channel, details): 
     self.channel = channel 
     self.details = details 
     threading.Thread.__init__ (self) 

    def run(self): 
     print('Received connection:', self.details[0]) 
     request = self.channel.recv(1024) 
     response = pickle.dumps(pickle.loads(request) * 2) 
     self.channel.send(response) 
     self.channel.close() 
     print('Closed connection:', self.details [ 0 ]) 

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
server.bind(('', 2727)) 
server.listen(5) 

while True: 
    channel, details = server.accept() 
    ClientThread(channel, details).start() 

Y aquí es el cliente:

import pickle 
import socket 
import threading 

class ConnectionThread(threading.Thread): 
    def run(self): 
     client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     client.connect(('localhost', 2727)) 

     for x in range(10): 
      client.send(pickle.dumps(x)) 
      print('Sent:',str(x)) 
      print('Received:',repr(pickle.loads(client.recv(1024)))) 

     client.close() 

for x in range(5): 
    ConnectionThread().start() 

El servidor funciona muy bien, y cuando corro el cliente se conecta correctamente y comienza a enviar los números enteros y recibir ellos se duplicaron como se esperaba. Sin embargo, muy rápidamente excepciones a cabo:

Exception in thread Thread-2: 
Traceback (most recent call last): 
    File "C:\Python30\lib\threading.py", line 507, in _bootstrap_inner 
    self.run() 
    File "C:\Users\Imagist\Desktop\server\client.py", line 13, in run 
    print('Received:',repr(pickle.loads(client.recv(1024)))) 
socket.error: [Errno 10053] An established connection was aborted by the softwar 
e in your host machine 

El servidor continúa funcionando y recibe conexiones muy bien; solo el cliente se bloquea ¿Qué está causando esto?

EDIT: Tengo el cliente trabaja con el siguiente código:

import pickle 
import socket 
import threading 

class ConnectionThread(threading.Thread): 
    def run(self): 
     for x in range(10): 
      client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
      client.connect(('localhost', 2727)) 
      client.send(pickle.dumps(x)) 
      print('Sent:',str(x)) 
      print('Received:',repr(pickle.loads(client.recv(1024)))) 
      client.close() 

for x in range(5): 
    ConnectionThread().start() 

Sin embargo, todavía no entienden lo que está pasando. ¿No es esto solo abrir y cerrar el socket un montón de veces? ¿No debería haber limitaciones de tiempo para eso (no debería poder abrir un socket tan pronto después de cerrarlo)?

+0

Hay algunos errores obvios en el código, parece suponer 1 enviar llamada por un lado resulta en 1 llamada recv en el otro lado, lo que podría no ser cierto, TCP es un protocolo de flujo, no es mensaje o paquete orientado. Sin embargo, no estoy seguro de cómo se relaciona eso con el mensaje de error. – leeeroy

+0

@leeroy Obviamente soy algo nuevo en esto, así que estoy completamente abierto a las críticas aquí. Pareces estar sugiriendo que no debería usar TCP porque es transmisión en lugar de orientado a paquetes; pero, ¿no puede uno representar un paquete simplemente como un flujo de datos muy corto? Sé que no es cómo debería * usarse, pero esto es solo para probar; obviamente, tengo la intención de transmitir muchos más datos que un solo entero. – Imagist

+0

@leeroy (continuación) Mi objetivo es trabajar para implementar algo como esto: http://www.mcwalter.org/technology/java/httpd/tiny/index.html solo en Python. – Imagist

Respuesta

7

Su cliente ahora está en lo correcto: desea abrir el socket, enviar los datos, recibir la respuesta y luego cerrar el socket.

El error El error original fue causado por el servidor cerrando el socket después de que envió la primera respuesta que causó que el cliente recibiera un mensaje de conexión cerrada cuando intentó enviar el segundo mensaje en la misma conexión.

Sin embargo, todavía no entiendo qué está pasando. ¿No es esto simplemente abriendo y cerrando el zócalo un montón de veces?

Sí. Esto es aceptable, si no la forma más eficaz de hacer las cosas.

¿No debería haber tiempo limitaciones a que (usted no debe estar capaz de abrir una toma tan poco tiempo después de cerrarlo )?

puede abrir un socket de cliente tan pronto como desee ya que cada vez que se abre un socket obtendrá un nuevo número de puerto local, lo que significa que las conexiones no interferirán. En el código del servidor anterior, se iniciará un nuevo hilo para cada conexión entrante.

Hay 4 partes para cada conexión IP (source_address, source_port, destination_address, destination_port) y este quad (como se lo conoce) debe cambiar para siempre. Todo, excepto source_port, está arreglado para un socket de cliente, de modo que eso es lo que el sistema operativo cambia para usted.

sockets de servidor de apertura es más problemático - si desea abrir un nuevo socket de servidor rápidamente, su

server.bind(('', 2727)) 

anteriores, entonces usted necesita para leer sobre SO_REUSEADDR.

-15

Así no se aprende la programación de redes python. Nadie que haga algo serio alguna vez programará así, así que estás aprendiendo a NO hacer la programación de redes de python.

  1. Los zócalos son de muy bajo nivel, y python es un lenguaje de alto nivel. Luego, para hacer la programación de la red python, de forma pitónica, debe evitar ocuparse por completo de los sockets y dejar eso en algún módulo o paquete. Si desea aprender cómo funcionan las cosas de bajo nivel, estudiar las implementaciones existentes es esencial de todos modos, por lo que es esencial aprender high-level library.
  2. pickle no es realmente cómo serializar objetos de pitón para enviarlos por el cable. Se trata de un problema de seguridad potencial que no se debe tener en cuenta, ya que se puede crear un paquete falso en escabeche que ejecuta código arbritary cuando está descosido. Es mejor utilizar un método de serialización seguro, ya que hay muchos disponibles, como llamar al str() en el objeto entero y int() en el otro lado.
  3. Para atender/escuchar a varios clientes al mismo tiempo, no use el enhebrado. En particular, nunca use el enfoque de "un hilo por conexión" que parece estar usando. No escala como crees. Dado que el uso de subprocesos también es propenso a errores y difícil de depurar, y no aporta absolutamente ninguna ventaja a sus resultados finales, bringing problems instead, intente evitarlos por completo.Los sockets (y por lo tanto higher level libraries como se describe en el elemento 1) pueden funcionar en modo no bloqueante, donde puede operar mientras se está ejecutando otro código, y eso se puede hacer sin utilizar los hilos.

acabo de ver su comentario sobre la cuestión:

@leeroy (continuación) Mi objetivo es trabajar para implementar algo como esto: http://www.mcwalter.org/technology/java/httpd/tiny/index.html sólo en Python

Bueno, aquí hay una implementación funcional:

from SimpleHTTPServer import SimpleHTTPRequestHandler as RH 
from SocketServer import TCPServer 

print "serving current directory at port 8000" 
TCPServer(("", 8000), RH).serve_forever() 
+18

-1. No creo que haya necesidad de una respuesta tan hostil, especialmente para alguien nuevo en Python. – dcrosta

+0

@dcrosta: lo siento, pero ¿dónde está mi respuesta hostil? – nosklo

+1

@dcrosta - Para el registro, no soy nuevo en Python, simplemente nuevo para la creación de redes. He respondido preguntas de Python durante un tiempo en SO. :) – Imagist

Cuestiones relacionadas