Есть ли способ выполнить команду, а затем продолжить программу без завершения команды

#python #c #python-3.x #ssh #paramiko

Вопрос:

Привет, я пытаюсь создать функцию, которая удаленно выполняет мой сценарий обнюхивания пакетов на моем raspberry pi, используя paramiko и ssh.

 def startPacketReceiver():
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(AutoAddPolicy())
    ssh.connect(RECV_IP_ADDRESS, username="pi", password="raspberry")
    ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("sudo gcc Code/test.c amp;amp; sudo ./a.out")
    print("Done")
 

Файл test.c — это сценарий поиска пакетов. Он завершится только с помощью CTRL-C (или эквивалентного метода). Это не заканчивается естественным/в конечном итоге.

Я хочу иметь возможность запустить приемник, а затем выйти из приемника, например:

 startPacketReceiver()
...
stopPacketReceiver()
 

В настоящее время, когда я запускаю скрипт python, я никогда не получаю сообщение о печати «Готово», что означает, что программа зависает на exec_command и не будет продолжаться до тех пор, пока она не будет завершена.

Дополнительная информация

Файл test.c циклически повторяется бесконечно, по существу:

 while(1)
{
    saddr_size = sizeof saddr;
    //Receive a packet
    data_size = recvfrom(sock_raw , buffer , 65536 , 0 , amp;saddr , (socklen_t*)amp;saddr_size);
    //fprintf(stderr,"%d",data_size);
    if(data_size <0 )
    {
        fprintf(stderr,"Failed to get packetn");
        printf("Recvfrom error , failed to get packetsn");
        return 1;
    }
    //Now process the packet
    ProcessPacket(buffer , data_size);
}
 

и поэтому, чтобы остановить это, вы должны нажать CTRL-C.

Комментарии:

1. Это странно, SSClient.exec_command что он не блокируется. Что, если ты сделаешь что-нибудь подобное sleep 60 amp;amp; ls . Он также висит в течение 60 секунд?

2. @MartinPrikryl Программа ждет 60 секунд, прежде чем продолжить.

3. «не прибегая к потоковой передаче», если вы хотите делать 2 вещи одновременно, вам нужна какая-то форма параллелизма. Ваш основной выбор-многопоточный или многопроцессный. Создание второго процесса, безусловно, можно рассматривать как «обращение к потоковой передаче», поэтому не совсем ясно, что вы хотите сделать. Вы можете либо запустить отдельный поток в том же процессе, либо создать новые потоки в новом процессе.

4. if(data_size <0 ) : если read() или recv() возвращают -1, вы должны проверить errno. Это может быть EINTR/EAGAIN

5. Какая система и оболочка у вас есть на сервере? В Ubuntu и bash я немедленно «заканчиваю» с stdin, stdout, stderr = ssh.exec_command("sleep 60 amp;amp; ls"); print("Done");

Ответ №1:

Вам нужно отправить свой пароль в sudo команду. Пожалуйста, включите tty режим для выполнения вашей команды, передав get_pty = True аргумент exec_command вызову функции. А затем вам нужно передать свой пароль через ssh_stdin файловый интерфейс.

 def startPacketReceiver():
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(AutoAddPolicy())
    ssh.connect(RECV_IP_ADDRESS, username="pi", password="raspberry")
    ssh.stdin, ssh_stdout, ssh_stderr = ssh.exec_command("gcc Code/test.c amp;amp; sudo ./a.out", get_pty=True)
    print("raspberry", ssh_stdin) # Your password for sudo command
    print("Done")
    return ssh, ssh_stdin, ssh_stdout, ssh_stderr
 

А затем вы можете написать свой stopPacketReceiver для отправки сигнала Ctrl-C.

 def stopPacketReceiver(ssh, ssh_stdin, ssh_stdout, ssh_stderr):
    print('x03', file=ssh_stdin) # Send Ctrl-C signal
    print(ssh_stdout.read()) #print the stdout
    print(ssh_stderr.read())
 

Ответ №2:

Я предлагаю взглянуть на демона(3)

Затем вы можете записывать СИГНАЛЫ или повторно открывать стандартный ввод. Зависит от того, что вы хотели бы сделать со своим скриптом python. (Если вы не хотите использовать какой-либо python, любую библиотеку python, кроме sys и os)

Редактировать:

Я почти уверен, что когда скрипт python завершит работу, ssh-соединение, очевидно, закроется, и поэтому любая программа, запущенная на этом tty пользователем, который инициировал соединение, будет прекращена. По этой причине ваша программа на языке си нуждается в демонизации, и, возможно, потребуется изменить ее uid и/или euid.

Несмотря на это, я попытался воспроизвести ваш код и столкнулся с аналогичной проблемой: скрипт python запускал команду, а затем печатал «Готово», но когда я попытался прочитать stdout, весь сценарий был приостановлен. Я думаю, что он ждал, когда скрипт вернет статус. Поэтому я внес следующие изменения:

 try:
    port = '22'
  
    client = paramiko.SSHClient()
  
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  
    client.connect('<host_name>', port=22, username='<username>',
                   password='<password>')
  
    chan = client.get_transport().open_session()
    chan.get_pty()
    chan.exec_command("cd <script_directory>;
                ; gcc test.c; ./a.out")
    while True:
        print(chan.recv(1024))
  
finally:
    client.close()
 

Цикл while здесь предназначен для получения выходных данных программы на языке си.
Но если вы закроете скрипт на python, за ним последует программа на языке си.
Я не слишком много копался в этой библиотеке.

ПРАВКА 2:

Посмотри наверх, нохуп

если вы не хотите использовать подход демона.