Скрученные как клиент / сервер проблемы - PullRequest
2 голосов
/ 05 мая 2011

Я использую twisted для создания «клиент / сервер», программы, которая действует как клиент для получения некоторых данных, и как сервер для повторной отправки этих данных или просто для отправки других данных клиентам.

Я использую twistd и мой код для инициализации моих фабрик выглядит так:

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

Моя проблема в том, что клиентская часть не может подключиться (поскольку сервер недоступен), похоже, что он «блокирует» всю мою серверную часть. Все еще возможно обмениваться данными между моей серверной частью и другими клиентами, но это очень медленно ... (и когда моя клиентская часть может быть подключена, это нормально работает).

Заранее спасибо за любую помощь.

EDIT:

Вот мой код ServerFactory (много бесполезного кода ...):

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)

А вот клиентская фабрика с большим количеством бесполезного кода:

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

Если потребуется дополнительная информация, я выложу весь код в pastebin. И, я новичок в питоне И скрученный (но я раньше программировал на C или C ++)

1 Ответ

1 голос
/ 05 мая 2011

Есть две вещи, которые вы должны изменить сразу.Избавьтесь от time.sleep(30) звонков.Кроме того, вы интенсивно используете пул потоков, поэтому вы, вероятно, захотите увеличить его размер.Каждые 30 секунд вы создаете 5 потоков, и, поскольку размер пула потоков реактора по умолчанию равен 5, любые другие созданные вами потоки будут в конечном итоге ждать этих пяти. Я думаю, что из-за большого количества ожидающих потоков может быть причинойслужба работает медленнее или даже кажется блокируемой.

В краткосрочной перспективе вы можете просто создать свой собственный twisted.python.threadpool.Threadpool в вашем 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)

Однако в долгосрочной перспективе везде, где быВозможно, вам следует использовать асинхронный API для работы с вашими сервисами.

Например, ваш код checkHttpd можно сделать асинхронным с помощью twisted.web.client.Agent .Для PostgreSQL вы можете использовать txPostgres .Я не знаком с вашей службой scamd, описанной выше, поэтому подключение к ней с помощью асинхронного ввода-вывода может быть более сложным (т. Е. Вам может потребоваться написать асинхронную версию протокола для этой службы).

...