2009-10-16 43 views
1

我的代碼基本上需要啓動一個簡單的客戶端聊天服務器。服務器和客戶端可以互相交談。我已經得到了一切正確的實施,但我無法弄清楚如何在完成後關閉服務器。 (我知道它是ss.shutdown())。Python訪問BaseRequestHandler

我想現在基於兩個(類似"bye")之間共享的關鍵字來結束,但我不知道如果我能以某種方式從BaseRequestHandler發送郵件到我的SocketServershutdown()每當它接收到的信息。

最終,我的目標是將Tkinter合併成一個GUI,但我想讓其他所有東西都先工作,這是我第一次在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() 

是啊,我知道設置()是一個可怕的功能,現在與嘗試的和漁獲物,但它工作了,所以我打算以後解決它。

我的問題基本上是:我怎樣才能讓服務器根據收到的消息真正結束?如果可能,有沒有辦法在啓動後訪問請求處理程序?

回答

2

請修復您的代碼以使其正常工作,並且包含一些使用方法。您需要添加

class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): 
    pass 

因爲SocketServer實際上並沒有包含那個類(至少不是我的2.6或2.7版本)。相反,這是SocketServer definition的一個例子。

請包括如何啓動/使用代碼的例子。在這種情況下,開始你需要做的服務器:

ss.py SERVER localhost 8001 

和客戶端爲

ss.py localhost 8001 

如果你這樣做,那麼你不能做server_thread.setDaemon(真)因爲沒有其他線程正在運行,這意味着服務器將立即退出。

一旦這樣做了,解決辦法是添加你EchoServer.handle方法的調用(或二)self.server.shutdown()insdie,如:

while 1: 
     if recver.getStatus(): 
      sender.setStatus(True) 
      self.server.shutdown() 
      break 

但是,我不能讓那是爲了工作,而且我認爲這是因爲我遺漏了錯誤的東西,或者在你所做的事情上猜錯了。

你應該做的是搜索使用Python完成聊天服務器的其他人。使用谷歌我發現http://www.slideshare.net/didip/socket-programming-in-python,當然還有其他人。另外,如果你打算混合GUI和線程編程,那麼你應該看看基於這個的例子。當我搜索「tkinter聊天」時有很多點擊。此外,你可能想看看扭曲,這已經解決了很多這些問題。

有什麼問題?那麼,例如,你可能想要一個SO_REUSEADDR套接字選項。

1

爲每個新請求創建請求處理程序對象。所以你必須在服務器中存儲「完成」標誌,而不是處理程序。類似以下內容:

class EchoServer(SocketServer.BaseRequestHandler): 
    ... 
    def setDone(self): 
     self.server.setDone() # or even better directly self.server.shutdown()