デモンストレーションされたサーバーでのPythonサブプロセスデッドロック

私は、darのリモートバックアップサーバを設定しようとしています。これらの行に沿って 。可能であればPythonですべてのパイプ処理をしたいのですが、そのことについて別の質問をしました。

subprocess.Popen(cmd、shell = True)にnetcatを使用すると、darサイトの例のように差分バックアップを作成することに成功しました。唯一の2つの問題は次のとおりです。

  1. この方法でポート番号を動的に割り当てる方法がわかりません。
  2. バックグラウンドでサーバーを実行すると失敗します。なぜですか?

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

ここに私のコードです:

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

サーバー上で起こることは次のとおりです。

$ 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

クライアントもハングアップするので、キーボード割り込みでそれを強制終了する必要があります。

1
なぜPythonは関与する必要がありますか? dar - | nc および nc -l | dar はずっと簡単です。
追加された 著者 Gringo Suave,
cronの何が問題なの?私はソケットのためにncとpythonの両方を使用するという点は見ていません。
追加された 著者 Gringo Suave,
@gringo、それはよりシンプルなようですが、私はすべてのバックアップを手動で呼び出す必要はありません。 Cronは十分にスマートではありません。 bashでバックアップサーバをコーディングするのはかなり苦しいでしょう。だから、あなたは何を提案していますか?
追加された 著者 Aryeh Leib Taurog,

2 答え

私は失ったものを切ってやり直すだろう。この解決策の試みは非常に複雑でクラージーです。この分野には多くの既製のソリューションがあります。

ハードウェアのための簡単なルート、rsync + sshを使いたい場合、Fwbackupsはうまく聞こえます。

1
追加された
実践的アプローチのために+1。私は残念なことに、このような技術的な挑戦が私を困惑させているとき、眠れない。私はバキュラとアマンダを考えましたが、自分のものを転がすのと同じくらい長く私を理解するのに時間がかかりそうです。魅力的だったrsyncの問題は、darと同じくらい頻繁に正しいことをやっていないし、darを使って私のバックアップを暗号化してアマゾンs3に簡単に貼り付けることができるということです。
追加された 著者 Aryeh Leib Taurog,
  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
追加された