şeytanlaştırılmış sunucuda python alt işlem çıkmazı

Bu satırlar boyunca, uzak bir uzaktan yedekleme sunucusu kurmaya çalışıyorum./a>. Mümkünse tüm boruları python ile yapmak isterdim, ancak bu konuda bir ayrı bir soru sordum .

subprocess.Popen (cmd, shell = True) 'da netcat kullanarak, dar sitedeki örneklerde olduğu gibi, bir diferansiyel yedekleme yapmayı başardım. Sadece iki problem:

  1. Bağlantı noktası numaralarını bu şekilde dinamik olarak nasıl atacağımı bilmiyorum
  2. Sunucuyu arka planda çalıştırırsam başarısız olur. Neden?

Update: This doesn't seem to be related to netcat; it hangs even without netcat in the mix.

İşte kodum:

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

İşte sunucuda ne olacak?

$ 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

İşte müşteride ne var?

$ 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

İstemci de kilitleniyor ve bir klavye kesmesiyle onu öldürmem gerekiyor.

1
Python neden dahil edilmeli? dar - | nc ve nc -l | dar çok daha basit görünüyor.
katma yazar Gringo Suave, kaynak
Cron'un nesi var? Yuvalar için nc ve python kullanma noktasını, neden biri veya diğerini kullanmıyorum?
katma yazar Gringo Suave, kaynak
@ gringo, görünüyor daha basit, ancak tüm yedeklerimi el ile çağırmak istemiyorum. Cron yeterince akıllı değil. Bash içinde bir yedek sunucu kodlamak oldukça acı verici olurdu. Peki tam olarak ne önerirsin?
katma yazar Aryeh Leib Taurog, kaynak

2 cevap

Kaybımı keserim ve baştan başlarım. Bu çözüm girişimi çok karmaşık ve kludgy. Bölgede birçok hazır çözüm var:

Fwbackups kolay yol almak istiyorsanız, sert çekirdek için rsync + ssh iyi geliyor.

1
katma
Pragmatik yaklaşım için +1. Ne yazık ki böyle bir teknik meydan okuma beni şaşırtıyorsa ben de uyuyamıyorum. Bacula ve Amanda'yı düşündüm, ama sanırım onları kendi başıma yuvarlayacağı kadar uzun sürecek. Aynı zamanda cazip olan rsync ile ilgili problem, doğru olanı hemen hemen sık sık yapmaz, ayrıca ben de yedeklememi şifreleyebilir ve onları kolayca sımsıkıya yapıştırabilirim.
katma yazar Aryeh Leib Taurog, kaynak
  1. Use Popen.communicate() instead of Popen.wait().

    The python documentation for wait() states:

    Warning: This will deadlock if the child process generates enough output to a stdout or stderr pipe such that it blocks waiting for the OS pipe buffer to accept more data. Use communicate() to avoid that.

  2. Dar and its related executables should get a -Q if they aren't running interactively.

  3. When syncronizing multiple processes, make sure to call communicate() on the 'weakest link' first: dar_slave before dar_xform and dar before cat. This was done correctly in the question, but it's worth noting.

  4. Clean up shared resources. The client process is holding open a socket from which dar_xform is still reading. Attempting to send/recv data on the initial socket after dar and friends are finished without closing that socket will therefore cause a deadlock.

Here is a working example which doesn't use shell=True or netcat. An advantage of this is I can have the secondary ports assigned dynamically and therefore could conceivably serve multiple backup clients simultaneously.

1
katma