Python, пока цикл приостанавливается

Я пытаюсь сделать несколько циклов, но почему-то они не работают. Я уже искал в Интернете, но ни одна из проблем, которые я нашел, не имеет такой же проблемы.

Итак, вот код, содержащий только необходимую информацию. Я в основном открываю сокет, даю ввод (i\n) и получаю вывод на первом этапе. Я хочу продолжать получать вывод до тех пор, пока на выходе не появятся определенные символы xxx. Затем я хочу перейти к оператору elif в следующем цикле.

def netcat(h, p):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((h,p))

    i = 0
    a = True
    while a == True:
        socket_list=[sys.stdin, s]
        r,w,x = select.select(socket_list, [], [])

        if i==0:
            time.sleep(1)
            message = s.recv(1024)
            print(message)
            s.send("i\n")
            sys.stdout.flush()

            while "xxx" not in message:
                message = s.recv(1024)
                print(message)
            i+=1
        elif i==1:
            print("+++++++++++++++++++++++++++")
                        i+=1

        print("hello")

    server.close()

Я ожидаю, что код будет печатать сообщение из оператора if, затем печатать Привет, затем сообщение из оператора elif, а затем Привет снова и снова, потому что цикл while все еще активен. Таким образом, это ожидаемый результат:

message
hello
+++++++++++++++++++++++++++
hello
hello
hello
hello...

Что он действительно печатает, так это

message
hello

и тогда это заканчивается.

Я узнал, что если я прокомментирую следующие строки:

                while "xxx" not in message:
                    message = s.recv(1024)
                    print(message)

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

Так как был запрошен рабочий код, вот и полный код. Имя хоста и порт взяты из CTF, который все еще работает, поэтому вы будете взаимодействовать с CTF-сервером:

#!/usr/bin/env python

import socket
import time
import select
import sys

base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/  = "
hostname = "18.188.70.152"
port = 36150

def netcat(h, p):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((h,p))

    i = 0
    a = True
    b = True
    while a == True:
        socket_list=[sys.stdin, s]
        r,w,x = select.select(socket_list, [], [])

        if i==0:
            time.sleep(1)           
            message = s.recv(1024)      
            print(message)          
            s.send("i\n")           
            sys.stdout.flush()

            while "flag" not in message:
                message = s.recv(1024)
                print(message)
            txtfile = message[9:38]
            print(txtfile)
            i+=1
        elif i==1:
            print("+++++++++++++++++++++++++++")
            i+=1
        print("hello")

    server.close()


netcat(hostname, port)



Еще одна информация: при запуске кода в терминале кажется, что цикл while все еще открыт, поскольку терминал показывает только пустое место в конце, но не показывает обычную строку username@machine:folders (в Linux).

Loeli 10.04.2019 07:00

Пожалуйста, выложите рабочий код. В вашем коде есть несколько проблем...

oz123 10.04.2019 07:01

Кроме того, server нижняя часть вашего кода не определена.

oz123 10.04.2019 07:09
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
3
128
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я бы проверил ваш отступ, попытался установить и запустить autopep8 в вашем коде и посмотреть, решит ли это какие-либо из ваших проблем.

[править] пользователь обновил свой вопрос, и стало ясно, что это не ответ.

Ответ принят как подходящий

Вы смешиваете код на основе событий (select.select()) с блокирующим синхронным кодом (ваш маленький цикл while с s.recv()).

Если вы хотите, чтобы ваш код не блокировался, каждый recv() должен быть соединен с предшествующим select().

Не только это, но вы также должны проверить возвращаемые значения из select(). Только s.recv(), если s было в первом возвращаемом списке. Если вы s.recv() в любом другом случае, код также заблокируется при входящем звонке.

Обновлять:

Попробуйте что-нибудь вроде:

not_done = True
while not_done:
    read_sockets, _, _ = select.select([sys.stdin, s], [], [])

    if s in read_sockets:
        message = s.recv(1024)
        print(message)

        ... more code ...

        if 'flag' in message:
            ... react on flag ...

        if 'quit' in message:
            not_done = False

    ... processing of other sockets or file descriptors ...

Важным моментом является то, что в ветке if есть только этот одинs.recv(), который проверяет, было ли получено что-то обнаруженным select.

Внешний while просто вернется в ту же if ветку позже, когда будут получены дополнительные данные.

Обратите внимание, что обработка stdin вместе с кодом сокета сложна и, вероятно, также будет заблокирована в какой-то момент. Скорее всего, вам придется сначала перевести терминал в необработанный режим или что-то в этом роде, а затем быть готовым обрабатывать частичные строки самостоятельно, а также, возможно, также повторять ввод обратно пользователю.

Обновлять:

Если вы хотите что-то сделать, пока сообщение не было получено, вы можете дать тайм-аут select(), а затем выполнить другую обработку, если на сокете ничего не было получено. Что-то вроде этого:

say_hello_from_now_on = False

not_done = True
while not_done:
    read_sockets, _, _ = select.select([s], [], [], 1)

    if s in read_sockets:
        message = s.recv(1024)
        print(message)

        say_hello_from_now_on = True

    elif say_hello_from_now_on:
        print("hello")

Эй, спасибо за быстрый ответ. Не могли бы вы привести пример того, как select нужно сочетать с recv()?

Loeli 10.04.2019 07:11

@Loeli, попробуйте что-то вроде плана, которым я обновил ответ.

blubberdiblub 10.04.2019 07:23

Я попробовал это сейчас с вашим предложением и изменил цикл while, чтобы он содержал только один recv, но он все еще не работает. Если бы мне не понадобился стандартный ввод, как я мог бы улучшить код, чтобы он работал? Извините за все эти вопросы, но я немного новичок в этом.

Loeli 10.04.2019 07:35

Итак, вы хотите, чтобы он постоянно печатал приветствие, когда не было получено никакого сообщения? Вы можете добиться этого, используя вызов select() с тайм-аутом. Если read_sockets не содержит s, просто выведите hello. Или вы хотите, чтобы приветствие выводилось только после получения первого сообщения?

blubberdiblub 10.04.2019 07:44

@Loeli Я также добавил использование двух других списков из звонка select(), который я пропустил раньше, извините за это. С этой моей ошибкой код никогда бы не попал в recv ветку if.

blubberdiblub 10.04.2019 07:51

«Привет» было просто там, чтобы я мог проверить, приостановлен ли цикл while или нет. То, что я хочу сделать, это распечатать полученные данные на экране, затем отправить серверу сообщение «i\n», снова распечатать получение на экране, затем отправить серверу «n\n», распечатать на экране и т.д. . Что я сделал сейчас, так это вставил s.shutdown(socket.SHUT_WR) после внутреннего цикла while, и это сработало. Но я не уверен, что это правильный способ сделать это.

Loeli 10.04.2019 07:52

Правильный способ - не использовать внутренний цикл while. Вы просто полагаетесь на код, постоянно возвращающийся к вызову select, и если он получает 1 элемент, обрабатывайте только этот 1 элемент. А для более сложной обработки вы сохраняете состояние вместе с переменными, которые сообщают вам, как реагировать дальше.

blubberdiblub 10.04.2019 07:54

Теперь у меня все работает, большое спасибо! Еще один вопрос, чтобы немного прояснить ситуацию: - функция recv(1024) остановит все, пока не получит 1024 бит? -что делает функция выбора и что происходит с таймером?

Loeli 10.04.2019 08:06

Нет, recv(1024) не будет ждать 1024 байта. Он получит все, что находится в приемном буфере, но только вплоть до 1024 байта. Если данные поступают с достаточно высокой скоростью, recv(1024) вернет только первые 1024 и оставит оставшиеся данные в приемном буфере для возврата вызова следующийrecv() (т. е. они не будут потеряны, а только разделятся).

blubberdiblub 10.04.2019 08:09

select.select() должным образом ожидает, пока что-то произойдет со всеми файловыми дескрипторами и сокетами, которые вы ему предоставите. Это особенно важно, если у вас их несколько одновременно, потому что вы не знаете заранее, на каком из них что-то произойдет дальше. Но это также важно, если вы хотите параллельно выполнять другую периодическую работу, для чего и нужен тайм-аут. Без тайм-аута select() будет ждать, пока что-то не произойдет, возможно, бесконечно. С тайм-аутом он установит ограничение на то, как долго он будет ждать, даже если не было активности на сокетах или файловых дескрипторах.

blubberdiblub 10.04.2019 08:11

Другие вопросы по теме