1

私のコードは基本的に、クライアントとの単純なチャットサーバーを起動する必要があります。サーバーとクライアントが相互に通信できる場所。すべてが正しく実装されましたが、完了するたびにサーバーをシャットダウンする方法がわかりません。(私はそれがだと知っていss.shutdown()ます)。

2人で共有しているキーワード(のようなもの)に基づいて今すぐ終了したいのですが、メッセージを受信するたびに、からに"bye"メッセージを送信できるかどうかわかりません。SocketServerBaseRequestHandlershutdown()

最終的に、私の目標はTkinterGUIを作成するために組み込むことですが、他のすべてを最初に機能させたいと思っていました。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()

ええ、私はsetup()がtryとcatchsで今のところひどい関数であることを知っています、しかしそれは今のところ機能するので、後でそれを修正するつもりでした。

私の質問は基本的に、受信したメッセージに基づいてサーバーを実際に終了させるにはどうすればよいですか?可能であれば、要求ハンドラーの開始後にアクセスする方法はありますか?

4

2 に答える 2

2

動作するようにコードを修正し、それを使用する方法を含めてください。追加する必要があります

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

SocketServerには実際にはそのクラスが含まれていないため(少なくとも私のバージョンの2.6または2.7には含まれていません)。代わりに、SocketServer定義の例です。

コードの起動/使用方法の例を含めてください。この場合、サーバーを起動するには、次のことを行う必要があります。

ss.py SERVER localhost 8001

とクライアントとして

ss.py localhost 8001

これを行うと、他のスレッドが実行されていないため、server_thread.setDaemon(True)を実行できなくなります。つまり、サーバーはすぐに終了します。

それが完了したら、解決策は、次のように、EchoServer.handleメソッドのself.server.shutdown()insdieに呼び出し(または2つ)を追加することです。

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

しかし、それをうまく機能させることはできません。それは、私が物事を間違って受け継いだか、あなたがしたことを間違って推測したためだと思います。

あなたがすべきことは、Pythonでチャットサーバーを実行した他の誰かを検索することです。Googleを使用して、 http://www.slideshare.net/didip/socket-programming-in-pythonを見つけましたが、確かに他にもあります。

また、GUIとスレッドプログラミングを組み合わせる場合は、それに基づいた例を調べる必要があります。「tkinterchat」を検索したところ、ヒット数が多かったです。また、これらの問題の多くをすでに解決しているツイストを調べたいと思うかもしれません。

どんな問題?たとえば、SO_REUSEADDRソケットオプションが必要になる可能性があります。

于 2009-10-16T17:38:11.933 に答える
1

リクエストハンドラオブジェクトは、新しいリクエストごとに作成されます。したがって、「完了」フラグをハンドラーではなくサーバーに格納する必要があります。次のようなもの:

class EchoServer(SocketServer.BaseRequestHandler):
    ...
    def setDone(self):
        self.server.setDone() # or even better directly self.server.shutdown()
于 2009-10-16T17:01:33.817 に答える