¿Cómo aborto un socket.recv() desde otro hilo en Python?
multithreading sockets (5)
Encontré una solución usando tiempos de espera. Eso interrumpirá el recv (en realidad antes de que expire el tiempo de espera, lo cual es bueno):
# Echo server program
import socket
from threading import Thread
import time
class ClientThread(Thread):
def __init__(self, clientSocke):
Thread.__init__(self)
self.clientSocket = clientSocket
def run(self):
while 1:
try:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
except socket.timeout:
# If it was a timeout, we want to continue with recv
continue
except:
break
self.clientSocket.close()
HOST = ''''
PORT = 6000
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serverSocket.bind((HOST, PORT))
serverSocket.listen(1)
clientSocket, addr = serverSocket.accept()
clientSocket.settimeout(1)
print ''Got a new connection from: '', addr
clientThread = ClientThread(clientSocket)
clientThread.start()
# Close it down immediatly
clientSocket.close()
Tengo un hilo principal que espera la conexión. Genera hilos de clientes que harán eco de la respuesta del cliente (telnet en este caso). Pero diga que quiero cerrar todos los sockets y todos los hilos después de un tiempo, como después de 1 conexión. ¿Cómo lo haría? Si hago clientSocket.close () desde el hilo principal, no dejará de hacer el recv. Solo se detendrá si primero envío algo a través de telnet, luego fallará haciendo más envíos y recvs.
Mi código se ve así:
# Echo server program
import socket
from threading import Thread
import time
class ClientThread(Thread):
def __init__(self, clientSocket):
Thread.__init__(self)
self.clientSocket = clientSocket
def run(self):
while 1:
try:
# It will hang here, even if I do close on the socket
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
except:
break
self.clientSocket.close()
HOST = ''''
PORT = 6000
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serverSocket.bind((HOST, PORT))
serverSocket.listen(1)
clientSocket, addr = serverSocket.accept()
print ''Got a new connection from: '', addr
clientThread = ClientThread(clientSocket)
clientThread.start()
time.sleep(1)
# This won''t make the recv in the clientThread to stop immediately,
# nor will it generate an exception
clientSocket.close()
No estoy seguro pero quizás puedas buscar pares de conectores
No sé si es posible hacer lo que me pides, pero no debería ser necesario. Simplemente no lea desde el socket si no hay nada que leer; use select.select
para verificar el socket de datos.
cambio:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
a algo más como esto:
r, _, _ = select.select([self.clientSocket], [], [])
if r:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
EDITAR: Si desea evitar la posibilidad de que el socket se haya cerrado, socket.error
.
do_read = False
try:
r, _, _ = select.select([self.clientSocket], [], [])
do_read = bool(r)
except socket.error:
pass
if do_read:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
Sé que este es un hilo viejo y que probablemente Samuel resolvió su problema hace mucho tiempo. Sin embargo, tuve el mismo problema y encontré esta publicación mientras navegaba por google. Encontré una solución y creo que vale la pena agregarla.
Puede usar el método de apagado en la clase de socket. Puede evitar más envíos, recepciones o ambos.
socket.shutdown (socket.SHUT_WR)
Lo anterior evita futuros envíos, como un ejemplo.
Consulte los documentos de Python para obtener más información.
Debo pedir disculpas por los comentarios a continuación. El comentario anterior de @Matt Anderson funciona. Cometí un error al probarlo, lo que me llevó a mi publicación a continuación.
Usar tiempo de espera no es una solución muy buena. Puede parecer que despertar por un instante y luego volver a dormir no es gran cosa, pero he visto que afecta en gran medida el rendimiento de una aplicación. Usted tiene una operación que en su mayor parte quiere bloquear hasta que haya datos disponibles y, por lo tanto, duerma para siempre. Sin embargo, si quiere abortar por alguna razón, como cerrar su aplicación, entonces el truco es cómo salir. Para enchufes, puede usar seleccionar y escuchar en dos enchufes. Tu primaria, y una parada especial. Sin embargo, crear el shutdown es un poco doloroso. Tienes que crearlo. Tienes que conseguir que el socket de escucha lo acepte. Tienes que hacer un seguimiento de ambos extremos de este tubo. Tengo el mismo problema con la clase Cola sincronizada. Sin embargo, al menos puede insertar un objeto ficticio en la cola para activar el get (). Sin embargo, esto requiere que el objeto ficticio no se vea como tus datos normales. A veces me gustaría que Python tuviera algo así como la API de Windows WaitForMultipleObjects.