Хотите эмулировать функциональность socat в Python

Мне нужно отправить строку на определенный порт на локальном хосте с помощью python.

Я могу добиться этого, используя socat в командной строке, например:

cat <text file containing string to send> | socat stdin tcp-connect:127.0.0.1:55559

Я не хочу запускать команду socat как подкоманду, поэтому я хотел бы знать, как заставить это работать с помощью модуля python.

Мои попытки использовать сокеты не увенчались успехом. Ниже приведен сценарий, который я использовал, но который не достиг желаемого эффекта.

    import socket
    HOST, PORT = "127.0.0.1", 55559
    jsonString = '{"name":"VideoStreamStatus","parameters":{"name":"video_0_0"}}'

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    try:
        # Connect to server and send data
        print "Attempting connection"
        sock.connect((HOST, PORT))
        print "Sending json string"
        sock.sendall(jsonString)
        print "String sent"

    finally:
        sock.close()

    print "Sent:     {}".format(jsonString)

Сценарий Python выполнялся без каких-либо ошибок, но это не повлияло на процесс, который получал данные socat. Вывод скрипта Python ниже:

    Attempting connection
    Sending json string
    Sent:     {"name":"VideoStreamStatus","parameters":{"name":"video_0_0"}}

Есть ли что-то, что я делаю неправильно в сценарии сокета, или есть другой метод, который я могу использовать в Python? Буду признателен за любой совет. Спасибо.

Редактировать: сервер, на который я пытаюсь отправить строки, является частью программы C++, использующей акцептор boost asio для прослушивания tcp-соединений по определенному адресу и порту.


person BlooMeth    schedule 04.10.2016    source источник
comment
Ваш код отлично работает для меня. Мой сервер nc -l 55559 отображает строку json на своем стандартном выводе. Пожалуйста, опишите сервер, который вы используете, и что заставляет вас думать, что это не повлияло на процесс, который получал данные socat.   -  person Robᵩ    schedule 04.10.2016
comment
@Robᵩ Сервер, на который я пытаюсь отправить строки, является частью программы C ++, использующей акцептор boost asio для прослушивания TCP-соединений по определенному адресу и порту.   -  person BlooMeth    schedule 05.10.2016


Ответы (3)


Оказалось что-то очень простое. Строка, которую я отправлял с помощью socat (которую сервер успешно получал и обрабатывал), имела в конце новую строку. В строке, которую я отправлял через сокет Python, не было новой строки. После добавления новой строки в конец скрипта Python сервер получает строку, как и ожидалось.

Я понял, что после одного была новая строка, а не другая, после запуска скрипта сервера Python, прослушивающего другой порт и отправляющего строку с использованием обоих методов.

person BlooMeth    schedule 05.10.2016

Согласно справочной странице socat,

Когда один канал достигает EOF, часть записи другого канала отключается. Затем socat ждет timeout секунды перед завершением. По умолчанию 0,5 секунды.

Возможно, вам нужно отложить закрытие на 0,5 секунды, например:

finally:
    #sock.close()
    sock.shutdown(socket.SHUT_WR)
    time.sleep(0.5)
    sock.close()

Или, возможно, вам нужно принять сообщение о завершении работы сервера, например:

finally:
    #sock.close()
    sock.shutdown(socket.SHUT_WR)
    sock.recv(999999)
    sock.close()
person Robᵩ    schedule 04.10.2016
comment
Никак не влияет на результат. Спасибо, в любом случае. - person BlooMeth; 04.10.2016

Вы никогда не должны закрывать сокет сразу после записи в сокет: закрытие может проглотить еще неотправленные данные.

Правильный рабочий процесс называется мягкое завершение работы:

  • часть, которая хочет закрыть соединение, использует запись на сокете и продолжает чтение
  • другая часть обнаруживает 0 байтов, прочитанных из сокета, который рассматривается как конец файла. Он закрывает свой сокет
  • инициатор обнаруживает чтение 0 байт и может безопасно закрыть сокет

Таким образом, часть finally становится:

finally:
  try:
    sock.shutdown(socket.SHUT_WR)
    while True:
        dummy = sock.recv(1024)
        if len(dummy) == 0: break
  finally:
    sock.close()
person Serge Ballesta    schedule 04.10.2016
comment
Спасибо за совет, но внесение этих изменений не изменило результат, сервер по-прежнему не получает никаких сообщений. - person BlooMeth; 05.10.2016