Python accès à BaseRequestHandler
-
21-09-2019 - |
Question
Mon code a besoin essentiellement pour démarrer un simple serveur de chat avec un client. Lorsque le serveur et le client peut parler et-vient à l'autre. J'ai tout appris à être mis en œuvre correctement, mais je ne peux pas comprendre comment arrêter le serveur chaque fois que je suis fait. (Je sais que ss.shutdown()
est ça).
Je suis désireux de mettre fin à ce moment basé sur un mot-clé partagé entre les deux (quelque chose comme "bye"
), mais je ne sais pas si je peux en quelque sorte envoyer un message à mon SocketServer
de BaseRequestHandler
à shutdown()
chaque fois qu'il reçoit le message .
Finalement, mon objectif est d'intégrer Tkinter
de faire une interface graphique, mais je voulais faire tout le reste à travailler d'abord, ce qui est la première fois que traiter les sockets en Python.
from sys import argv, stderr
from threading import Thread
import socket
import SocketServer
import threading
import sys
class ThreadedRecv(Thread):
def __init__(self,socket):
Thread.__init__(self)
self.__socket = socket
self.__message = ''
self.__done = False
def recv(self):
while self.__message.strip() != "bye" and not self.getStatus():
self.__message = self.__socket.recv(4096)
print 'received',self.__message
self.setStatus(True)
def run(self):
self.recv()
def setStatus(self,status):
self.__done = status
def getStatus(self):
return self.__done
class ThreadedSend(Thread):
def __init__(self,socket):
Thread.__init__(self)
self.__socket = socket
self.__message = ''
self.__done = False
def send(self):
while self.__message != "bye" and not self.getStatus():
self.__message = raw_input()
self.__socket.send(self.__message)
self.setStatus(True)
def run(self):
self.send()
def setStatus(self,status):
self.__done = status
def getStatus(self):
return self.__done
class HostException(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class EchoServer(SocketServer.BaseRequestHandler):
def setup(self):
print self.client_address, 'is connected!'
self.request.send('Hello ' + str(self.client_address) + '\n')
self.__done = False
def handle(self):
sender = ThreadedSend(self.request)
recver = ThreadedRecv(self.request)
sender.start()
recver.start()
while 1:
if recver.getStatus():
sender.setStatus(True)
break
if sender.getStatus():
recver.setStatus(True)
break
def finish(self):
print self.client_address, 'disconnected'
self.request.send('bye client %s\n' % str(self.client_address))
self.setDone(True)
def setDone(self,done):
self.__done = done
def getDone(self):
return self.__done
def setup(arg1, arg2, arg3):
server = False
defaultPort,defaultHost = 2358,"localhost"
hosts = []
port = defaultPort
serverNames = ["TRUE","SERVER","S","YES"]
arg1 = arg1.upper()
arg2 = arg2.upper()
arg3 = arg3.upper()
if arg1 in serverNames or arg2 in serverNames or arg3 in serverNames:
server = True
try:
port = int(arg1)
if arg2 != '':
hosts.append(arg2)
except ValueError:
if arg1 != '':
hosts.append(arg1)
try:
port = int(arg2)
if arg3 != '':
hosts.append(arg3)
except ValueError:
if arg2 != '':
hosts.append(arg2)
try:
port = int(arg3)
except ValueError:
if arg3 != '':
hosts.append(arg3)
port = defaultPort
for sn in serverNames:
if sn in hosts:
hosts.remove(sn)
try:
if len(hosts) != 1:
raise HostException("Either more than one or no host "+ \
"declared. Setting host to localhost.")
except HostException as error:
print error.value, "Setting hosts to default"
return (server,defaultHost,port)
return (server,hosts[0].lower(),port)
def main():
bufsize = 4096
while len(argv[1:4]) < 3:
argv.append('')
settings = setup(*argv[1:4])
connections = (settings[1],settings[2])
print connections
if not settings[0]:
try:
mySocket = socket.socket(socket.AF_INET,\
socket.SOCK_STREAM)
except socket.error, msg:
stderr.write("[ERROR] %s\n" % msg[1])
sys.exit(1)
try:
mySocket.connect(connections)
except socket.error, msg:
stderr.write("[ERROR] %s\n" % msg[1])
sys.exit(2)
message = ""
print "Enter a message to send to the server. "+\
"Enter \"bye\" to quit."
sender = ThreadedSend(mySocket)
recver = ThreadedRecv(mySocket)
sender.start()
recver.start()
while 1:
if sender.getStatus():
recver.setStatus(True)
break
if recver.getStatus():
sender.setStatus(True)
break
else:
xserverhandler = EchoServer
serversocket = SocketServer.ThreadedTCPServer(\
connections,xserverhandler)
server_thread = Thread(target = serversocket.serve_forever)
server_thread.setDaemon(True)
server_thread.start()
# I would like to shut down this server whenever
# I get done talking to it.
"""while 1:
if xserverhandler.getDone():
print 'This is now true!'
serversocket.shutdown()
break"""
if __name__ == '__main__':
main()
Ouais, je sais que la configuration () est une fonction terribles en ce moment avec les captures de l'essai, mais il fonctionne pour l'instant, donc j'allais le corriger plus tard.
Ma question est fondamentalement: Comment puis-je obtenir le serveur pour mettre fin en fait basé sur un message qu'il reçoit? Si possible, est-il un moyen d'accéder à la demande Handler après qu'il a commencé?
La solution
S'il vous plaît corriger votre code afin qu'il fonctionne, et inclure une certaine façon de l'utiliser. Vous devez ajouter
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
pass
depuis SocketServer ne comprend pas vraiment cette classe (au moins pas dans ma version de 2.6 ni 2.7). Au lieu de cela, il est un exemple de la définition SocketServer .
S'il vous plaît inclure un exemple de la façon de démarrer / utiliser le code. vous devez faire dans ce cas pour démarrer le serveur:
ss.py SERVER localhost 8001
et le client comme
ss.py localhost 8001
Si vous faites cela, vous ne pouvez pas faire server_thread.setDaemon (vrai) parce qu'il n'y a pas d'autres threads en cours d'exécution, ce qui signifie que le serveur quitte immédiatement.
Une fois cela fait la solution consiste à ajouter un appel (ou deux) à self.server.shutdown () insdie de votre méthode EchoServer.handle, comme:
while 1:
if recver.getStatus():
sender.setStatus(True)
self.server.shutdown()
break
Cependant, je ne peux pas que le travail, et je pense que c'est parce que je hérité de mauvaises choses, ou devinais mal dans ce que vous avez fait.
Ce que vous devez faire est de rechercher quelqu'un d'autre qui a fait un serveur de chat en Python. En utilisant Google J'ai trouvé http://www.slideshare.net/didip/socket- la programmation en python et il y a certainement d'autres.
En outre, si vous allez mélanger GUI et la programmation par thread alors vous devriez regarder dans des exemples sur cette base. Il y a un certain nombre de hits quand je recherchais « tkinter chat ». En outre, vous voudrez peut-être examiner tordu, qui a résolu beaucoup de ces problèmes déjà.
Quels sont les problèmes? Eh bien, par exemple, vous voulez probablement une option prise SO_REUSEADDR.
Autres conseils
Demande objet de gestion est créé pour chaque nouvelle demande. Donc, vous devez stocker « fait » drapeau serveur, et non gestionnaire. Quelque chose comme ce qui suit:
class EchoServer(SocketServer.BaseRequestHandler):
...
def setDone(self):
self.server.setDone() # or even better directly self.server.shutdown()