简体   繁体   中英

Twisted as a client/server problems

I'm using twisted to create a "client/server", a programme which act as a client to get some data, and as a server to re-send this data or just to send other data to clients.

I'm using twistd and my code to initialize my factories look like that:

application = service.Application('monitorD', uid=0, gid=0)
factoryMonitord = ServerFactory(p)
internet.TCPServer(9000, factoryMonitord).setServiceParent(service.IServiceCollection(application))
#because I need to send some datas from client factory to clients of serverfactory
factoryScamd = ClientFactory(factoryMonitord)
internet.TCPClient("localhost", 8001, factoryScamd).setServiceParent(service.IServiceCollection(application))

My problem is when the client part cannot connect (because server is unavaiable), it's look like it "block" all my server part. It's still possible to communicate between my server part and other clients but it's really slow... (and when my client part can be connected it's juste work fine).

Thanks in advance for anyhelp.

EDIT:

Here's my ServerFactory code (a lot of useless code...):

class ServerFactory(protocol.ServerFactory):
    protocol = ServerProtocol

    def __init__(self, portal):
        #self.tp = ClientFactory.tp 
        self.tp = []
        self.portal = portal
        self.loop_vol_raid_areca = LoopingCall(self.checkVolRaidAreca)
        self.loop_vol_raid_areca.start(30)
        self.loop_services = LoopingCall(self.checkServices)
        self.loop_services.start(30)

    def buildProtocol(self, addr):
        p = protocol.ServerFactory.buildProtocol(self, addr)
        p.portal = self.portal
        return p

    def sendList(self, data):
        if data:
            if isinstance(data, list):
                for element in data:
                    if isinstance(element, list):
                        self.clean_data = "".join(element)
                self.sendToClients(self.clean_data)

    def sendToClients(self, data):
        print "SEND to MonitorC from MonitorD, tp:", self.tp
        if data:
            for tp in self.tp:
                self.protocol.sendLine(tp, data)

    def checkServices(self):
        self.scamd = threads.deferToThread(checkScamd)
        self.scamd.addCallback(self.sendToClients)
        self.httpd = threads.deferToThread(checkHttpd)
        self.httpd.addCallback(self.sendToClients)
        self.postgres = threads.deferToThread(checkPostgres)
        self.postgres.addCallback(self.sendToClients)

    def checkVolRaidAreca(self):
        self.vol = threads.deferToThread(check_vol_areca)
        self.vol.addCallback(self.sendList)
        self.event = threads.deferToThread(get_last_event_areca)
        self.event.addCallback(self.sendList)

And here's the client factory with a lot of useless code:

class ClientFactory(protocol.ClientFactory):
    protocol = ClientProtocol

    def __init__(self, MonitordFactory):
        self.tp = MonitordFactory.tp

    def clientConnectionFailed(self, connector, reason):
        print "Connection to scamd failed - retrying..."
        time.sleep(30)
        connector.connect()

    def clientConnectionLost(self, connector, reason):
        print "Connection to scamd lost - retrying..."
        time.sleep(30)
        connector.connect()

    def getCamList(self, data):
        cams_list = data.split("\x00")
        self.cams_array = []
        for i in cams_list:
            if str.find(i, "camera") != -1:
                i = i.split(" ")
                i = filter(lambda x: len(x)>0, i)
                self.cams_array.append(i)

    def checkCams(self, data):
        data = data.split(" ")
        for i in self.cams_array:
            if i[1] == data[2]:
                if data[3] == "-1":
                    msg = i[6] + " ERREUR -1"
                if data[3] == "0":
                    msg = i[6] + " ERREUR 0"
                if data[3] == "1":
                    msg = i[6] + " ERREUR 1"
                if data[3] == "2":
                    msg = i[6] + " ERREUR 2 (RECO)"
        return msg

If more information needed I will post the entire code to pastebin. AND, I'm a newbie at python AND twisted (but i used to code in C or C++)

There are two things you should be able to change right off the bat. Get rid of the time.sleep(30) calls. Also, you're heavily using the threadpool so you'll likely want to increase the size of it. Every 30 seconds you're creating 5 threads and because the reactor threadpool size defaults to 5 any other threads you create are going to end up waiting behind those 5. I'm thinking that having a bunch of queued up threads waiting may be why your service is running more slowly or even appearing to block.

In the short term you may just create your own twisted.python.threadpool.Threadpool in your ServerFactory:

class ServerFactory(protocol.ServerFactory):
    protocol = ServerProtocol

    def __init__(self, portal):
        # ...
        self.threadpool = ThreadPool(25, 50)

    def checkServices(self):
        # ...
        self.postgres = threads.deferToThreadPool(reactor, self.threadpool, checkPostgres)

However, in the long term wherever possible you should look into using an Asynchronous API for dealing with your services.

For example, your checkHttpd code could be made asynchronous by using twisted.web.client.Agent . For PostgreSQL you can use txPostgres . I am not familiar with your scamd service above so connecting to it with asynchronous IO may be more difficult (ie: you may have to write an asynchronous version of the protocol for that service).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM