سؤال

يحتاج الكود الخاص بي أساسًا إلى بدء تشغيل خادم دردشة بسيط مع عميل. حيث يمكن للخادم والعميل التحدث ذهابًا وإيابًا إلى بعضهما البعض. لقد حصلت على كل شيء ليتم تنفيذه بشكل صحيح ، لكن لا يمكنني معرفة كيفية إغلاق الخادم كلما انتهيت. (انا اعلم انه ss.shutdown()).

أرغب في النهاية الآن بناءً على كلمة رئيسية مشتركة بين الاثنين (شيء مثل "bye") ، لكنني لا أعرف ما إذا كان بإمكاني إرسال رسالة إلى بلدي بطريقة ما SocketServer من عند BaseRequestHandler ل shutdown() كلما استقبلت الرسالة.

في النهاية ، هدفي هو دمج Tkinter لصنع واجهة المستخدم الرسومية ، لكنني أردت أن أعمل كل شيء آخر أولاً ، وهذه هي المرة الأولى التي أتعامل فيها مع مآخذ في بيثون.

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()

نعم ، أعرف أن الإعداد () هو وظيفة فظيعة الآن مع المحاولة والمصيد ، لكنها تعمل في الوقت الحالي ، لذلك كنت سأصلحها لاحقًا.

سؤالي هو بشكل أساسي: كيف يمكنني الحصول على الخادم فعليًا بناءً على رسالة تتلقاها؟ إذا كان ذلك ممكنًا ، هل هناك طريقة للوصول إلى معالج الطلب بعد بدء تشغيله؟

هل كانت مفيدة؟

المحلول

يرجى إصلاح الرمز الخاص بك بحيث يعمل ، وتضمين طريقة لاستخدامه. تحتاج إلى إضافة

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 (صحيح) لأنه لا توجد مؤشرات ترابط أخرى تعمل ، مما يعني أن الخادم سيخرج على الفور.

بمجرد الانتهاء من ذلك ، فإن الحل هو إضافة مكالمة (أو اثنين) إلى self.server.shutdown () insdie من طريقة echoServer.handle ، مثل:

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

ومع ذلك ، لا يمكنني الحصول على ذلك للعمل ، وأعتقد أن ذلك لأنني ورثت الأمور خاطئة ، أو خمنت خطأ في ما فعلته.

ما يجب عليك فعله هو البحث عن شخص آخر قام بخادم دردشة في بيثون. باستخدام Google وجدت http://www.slideshare.net/didip/socket-programming-in-python وهناك بالتأكيد آخرون.

أيضًا ، إذا كنت ستختلط في واجهة المستخدم الرسومية والبرمجة الخيوط ، فيجب عليك النظر في أمثلة بناءً على ذلك. هناك عدد من الزيارات عندما بحثت عن "دردشة Tkinter". أيضًا ، قد ترغب في النظر إلى Twisted ، والتي حلت الكثير من هذه المشكلات بالفعل.

ما هي المشاكل؟ حسنًا ، على سبيل المثال ، من المحتمل أن تريد خيار SO_REUSEADDR Socket.

نصائح أخرى

يتم إنشاء كائن معالج الطلب لكل طلب جديد. لذلك عليك تخزين العلم "المنجز" في الخادم ، وليس المعالج. شيء مثل ما يلي:

class EchoServer(SocketServer.BaseRequestHandler):
    ...
    def setDone(self):
        self.server.setDone() # or even better directly self.server.shutdown()
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top