тупик подпроцесса Python на демонизированном сервере - PullRequest
1 голос
/ 28 октября 2011

Я пытаюсь настроить удаленный сервер резервного копирования для дар, по этим направлениям .Я действительно хотел бы сделать все трубопроводы с Python, если это возможно, но я задал отдельный вопрос об этом.

Используя netcat в subprocess.Popen(cmd, shell=True), мне удалось сделатьдифференциальное резервное копирование, как в примерах на сайте дар.Единственные две проблемы:

  1. Я не знаю, как динамически назначать номера портов таким образом
  2. Если я выполняю сервер в фоновом режиме, это дает сбой.Почему?

Обновление: Похоже, это не связано с netcat;в смеси он даже без netcat.

Вот мой код:

from socket import socket, AF_INET, SOCK_STREAM
import os, sys
import SocketServer
import subprocess

class DarHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        print('entering handler')
        data = self.request.recv(1024).strip()
        print('got: ' + data)
        if data == 'xform':
            cmd1 = 'nc -dl 41201 | dar_slave archives/remotehost | nc -l 41202'
            print(cmd1)
            cmd2 = 'nc -dl 41200 | dar_xform -s 10k - archives/diffbackup'
            print(cmd2)
            proc1 = subprocess.Popen(cmd1, shell=True)
            proc2 = subprocess.Popen(cmd2, shell=True)
            print('sending port number')
            self.request.send('41200')
            print('waiting')
            result = str(proc1.wait())
            print('nc-dar_slave-nc returned ' + result)
            result = str(proc2.wait())
            print('nc-dar_xform returned ' + result)
        else:
            result = 'bad request'
        self.request.send(result)
        print('send result, exiting handler')

myaddress = ('localhost', 18010)
def server():
    server = SocketServer.TCPServer(myaddress, DarHandler)
    print('listening')
    server.serve_forever()

def client():
    sock = socket(AF_INET, SOCK_STREAM)
    print('connecting')
    sock.connect(('localhost', 18010))
    print('connected, sending request')
    sock.send('xform')
    print('waiting for response')
    port = sock.recv(1024)
    print('got: ' + port)
    try:
        os.unlink('toslave')
    except:
        pass
    os.mkfifo('toslave')
    cmd1 = 'nc -w3 localhost 41201 < toslave'
    cmd2 = 'nc -w3 localhost 41202 | dar -B config/test.dcf -A - -o toslave -c - | nc -w3 localhost ' + port
    print(cmd2)
    proc1 = subprocess.Popen(cmd1, shell=True)
    proc2 = subprocess.Popen(cmd2, shell=True)
    print('waiting')
    result2 = proc2.wait()
    result1 = proc1.wait()
    print('nc<fifo returned: ' + str(result1))
    print('nc-dar-nc returned: ' + str(result2))
    result = sock.recv(1024)
    print('received: ' + result)
    sock.close()
    print('socket closed, exiting')

if __name__ == "__main__":
    if sys.argv[1].startswith('serv'):
        server()
    else:
        client()

Вот что происходит на сервере:

$ python clientserver.py serve &
[1] 4651
$ listening
entering handler
got: xform
nc -dl 41201 | dar_slave archives/remotehost | nc -l 41202
nc -dl 41200 | dar_xform -s 10k - archives/diffbackup
sending port number
waiting

[1]+  Stopped                 python clientserver.py serve

Вот что происходит на клиенте:

$ python clientserver.py client
connecting
connected, sending request
waiting for response
got: 41200
nc -w3 localhost 41202 | dar -B config/test.dcf -A - -o toslave -c - | nc -w3 localhost 41200
waiting
FATAL error, aborting operation
Corrupted data read on pipe
nc<fifo returned: 1
nc-dar-nc returned: 1

Клиент также зависает, и я должен убить его с помощью прерывания клавиатуры.

Ответы [ 2 ]

1 голос
/ 28 октября 2011
  1. Используйте Popen.communicate() вместо Popen.wait().

    Документация python для wait () сообщает:

    Предупреждение: Это приведет к взаимоблокировке, если дочерний процесс генерирует достаточно вывода в канал stdout или stderr, так что он блокирует ожидание буфера канала ОС для приема большего количества данных. Используйте connect (), чтобы избежать этого.

  2. Дар и связанные с ним исполняемые файлы должны получить -Q , если они не работают в интерактивном режиме.

  3. При синхронизации нескольких процессов обязательно сначала вызовите communicate() для «самого слабого звена»: dar_slave до dar_xform и dar до cat. Это было сделано правильно в вопросе, но стоит отметить.

  4. Очистить общие ресурсы. Клиентский процесс держит открытый сокет, из которого dar_xform все еще читает. Попытка отправить / получить данные в исходном сокете после того, как dar и friends закончили без закрытия этого сокета, приведет к взаимоблокировке.

Вот рабочий пример , в котором не используется shell=True или netcat. Преимущество этого состоит в том, что я могу назначать вторичные порты динамически и, следовательно, возможно обслуживать несколько клиентов резервного копирования одновременно.

1 голос
/ 28 октября 2011

Я бы сократил свои потери и начал бы сначала. Эта попытка решения очень сложна и клудна. В области есть много готовых решений:

Fwbackups звучит хорошо, если вы хотите выбрать легкий путь, rsync + ssh для жесткого ядра.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...