Come uccidere server X senza testa iniziato con Python?
-
20-09-2019 - |
Domanda
Voglio ottenere screenshot di una pagina web in Python. Per questo sto usando http://github.com/AdamN/python-webkit2png/ .
newArgs = ["xvfb-run", "--server-args=-screen 0, 640x480x24", sys.argv[0]]
for i in range(1, len(sys.argv)):
if sys.argv[i] not in ["-x", "--xvfb"]:
newArgs.append(sys.argv[i])
logging.debug("Executing %s" % " ".join(newArgs))
os.execvp(newArgs[0], newArgs)
In sostanza chiamate Xvfb-run con i args corretti. Ma man xvfb
dice:
Note that the demo X clients used in the above examples will not exit on their own, so they will have to be killed before xvfb-run will exit.
Quindi questo significa che questo script ???> se tutta questa faccenda è in un ciclo, (per ottenere screenshot multipli) a meno che il server X viene ucciso. Come posso fare ciò?
Soluzione
La documentazione per os.execvp
afferma:
Queste funzioni tutti eseguono una nuova programma, sostituendo l'attuale processi; non restituiscono. [..]
Così, dopo aver chiamato os.execvp
nessun altra dichiarazione nel programma verrà eseguito. Si consiglia di utilizzare subprocess.Popen
invece:
Il modulo
subprocess
permette di di spawn nuovi processi, si collegano a loro ingresso / uscita / conduttori di errore, ed ottenere i loro codici di ritorno. Questo modulo intende sostituire molti altri, moduli e funzioni più anziani, come ad esempio:
Utilizzando subprocess.Popen
, il codice per eseguire xlogo
nel server framebuffer X virtuale diventa:
import subprocess
xvfb_args = ['xvfb-run', '--server-args=-screen 0, 640x480x24', 'xlogo']
process = subprocess.Popen(xvfb_args)
Ora il problema è che xvfb-run
lancia Xvfb
in un processo in background. Chiamando process.kill()
non ucciderà Xvfb
(almeno non sulla mia macchina ...). Sono stato trafficando con questo un po ', e finora l'unica cosa che funziona per me è:
import os
import signal
import subprocess
SERVER_NUM = 99 # 99 is the default used by xvfb-run; you can leave this out.
xvfb_args = ['xvfb-run', '--server-num=%d' % SERVER_NUM,
'--server-args=-screen 0, 640x480x24', 'xlogo']
subprocess.Popen(xvfb_args)
# ... do whatever you want to do here...
pid = int(open('/tmp/.X%s-lock' % SERVER_NUM).read().strip())
os.kill(pid, signal.SIGINT)
Quindi, questo codice legge l'ID del processo di Xvfb
da /tmp/.X99-lock
e invia il processo di un interrupt. Funziona, ma non produrrà un messaggio di errore ogni tanto (suppongo si può ignorare, però). Speriamo che qualcun altro in grado di fornire una soluzione più elegante. Cin cin.