Как прослушивать сокет, когда приложение работает в gtk.main()?

Я пытался искать, но ничего не работает. Например:

Отдельные потоки

В настоящее время я пишу простое коммуникационное приложение на Python2.7 с PyGTK. У меня есть фоновый процесс, который прослушивает сокет в цикле while. Я хочу отображать сообщение, когда я получаю его с сервера. Но когда я запускаю gtk.main(), он, очевидно, снова начинает зацикливаться, поэтому мой цикл прослушивания не работает. Мне нужно отображать новое окно для каждого сообщения или закрывать старое окно и отображать новое окно со всеми непрочитанными сообщениями. Могу ли я каким-то образом отобразить окно (или более одного окна) и не блокировать цикл прослушивания?

Решение IOChannel

 while True: #listening loop
  print 'Start'
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
  sock.bind((socket.gethostname(), 80))
  sock.listen(2)
  conn, address = sock.accept()
  conn.sendall('200 OK')
  fd = conn.fileno() #Make file descriptor from socket
  gio_channel = glib.IOChannel(fd) #Pass it to IOChannel

  if(new_message):
    #display message with gtk.main()
  else
    #Do something else like update file

subprocess.Popen решение

while True: #listening loop
  print 'Start'
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
  sock.bind((socket.gethostname(), 80))
  sock.listen(2)
  conn, address = sock.accept()
  conn.sendall('200 OK')
  all_json = conn.recv(2048)

  if(new_message):
    # This script run pygtk app in the background
    subprocess.Popen(['python', 'communication_app.py'])
  else
    #Do something else like update file

person Morasiu    schedule 13.11.2017    source источник


Ответы (1)


Вы можете попробовать использовать GIOChannel GLib (GLib.IOChannel в документе Python) для обработки сокетов как источника событий en (a GSource). Затем используйте g_io_create_watch (GLib.IOChannel.add_watch в Python) для интеграции в основной цикл GTK+.

В библиотеке Gio у вас также есть много более сложных вещей для обработки сокетов:

person liberforce    schedule 13.11.2017
comment
Привет! Спасибо за помощь. У меня только один вопрос. Итак, gtk.man() должен быть в часах или сокет должен быть в часах? - person Morasiu; 14.11.2017
comment
gtk.main создает основной цикл событий. Там вы можете просмотреть источники событий, такие как тайм-ауты, простои или каналы ввода-вывода. Основной цикл позаботится о вызове ваших обратных вызовов при срабатывании событий в этих источниках событий. Вы даже можете создать свои собственные источники событий, создав новые GSource. Документация C для g_io_add_watch говорит: Adds the GIOChannel into the default main loop context with the default priority так что вы в основном говорите основному циклу: вот новый источник событий, который я хочу поймать, вызывайте связанный обратный вызов, когда событие происходит в этом источнике. - person liberforce; 14.11.2017
comment
Ok. А как передать socket как fd в gio_channel = glib.IOChannel(sock)? Я получаю TypeError: требуется целое число - person Morasiu; 14.11.2017
comment
developer.gnome.org/glib/ стабильно/ - person liberforce; 14.11.2017
comment
Вызовите glib.IOChannel.unix_new(fd) с файловым дескриптором вашего сокета. - person liberforce; 14.11.2017
comment
Да, я пробовал, но получаю AttributeError: type object 'glib.IOChannel' has no attribute 'unix_new - person Morasiu; 14.11.2017
comment
Проверьте свой импорт. Это работает для меня: python -c "import gi; gi.require_version('GLib', '2.0'); from gi.repository import GLib; help(GLib.IOChannel.unix_new)" - person liberforce; 14.11.2017
comment
Нет, эта команда работает для меня как с Python 2.7, так и с Python 3. - person liberforce; 15.11.2017
comment
Я сейчас работаю над терминалом, и установка новых библиотек может быть проблематичной. У меня есть эта библиотека на Python 3, но не на Python 2.7. Мне действительно нужны некоторые решения:/ - person Morasiu; 15.11.2017
comment
Вам не кажется, что на самом деле запуск командной строки, которую я вам дал, и копирование/вставка фактического результата были бы более продуктивными, чем нытье? У меня нет хрустального шара, чтобы знать, как настроена ваша система или вы что-то опечатались... - person liberforce; 15.11.2017
comment
Кстати, в документе четко указано, что GTK+ 3 (и, следовательно, зависимости, такие как GLib) работают как с Python 2, так и с Python 3, но нет такой вещи, как у меня есть эта библиотека на Python 3, но не на Python 2.7. См. python-gtk-3-tutorial.readthedocs.io. /ru/последние/ - person liberforce; 15.11.2017
comment
Я сделал и получил ImportError: No module named gi. Так же, как я сказал. У меня нет этого модуля. - person Morasiu; 15.11.2017
comment
О, мой плохой. Я просмотрел много вопросов и не понял, что вы используете pygtk (имеется в виду, что вы программируете в GTK+ 2), а не pygobject (для GTK+ 3). Последний выпуск pygtk датирован 2011 годом: это старый, устаревший и устаревший проект, который никто не должен использовать в новой разработке. Тем более, что GTK 4 находится в стадии подготовки и, скорее всего, будет выпущен в 2019 году. При этом pygtk и pygobject — это две разные привязки, поэтому API не одно и то же. - person liberforce; 15.11.2017
comment
Да, знаю. Но я работаю в закрытой, ограниченной среде на основе старой, настроенной версии арки с xfce. - person Morasiu; 15.11.2017
comment
Затем вы получите помощь для IOChannel с python -c "import glib; help(glib.IOChannel)". Однако нет метода unix_new, поэтому лучшее, что вы можете сделать, это либо попытаться передать fd конструктору (недокументированному), либо попытаться найти старый пример кода, который использует IOChannel с сокетом, либо посмотреть код pyglib и увидеть, что он на самом деле делает и ожидает. - person liberforce; 15.11.2017
comment
Я попытаюсь. Спасибо за все. Знаете ли вы, есть ли способ... я не знаю, запускать все в отдельных потоках или что-то в этом роде? По крайней мере, это решило бы часть проблемы. - person Morasiu; 15.11.2017
comment
Если у вас есть проблема и вы пытаетесь решить ее с помощью потоков, то у вас есть две проблемы. GTK не является потокобезопасным, поэтому, если вы начнете использовать потоки неправильным образом, вы выстрелите себе в ногу. Если у вас нет пользовательского интерфейса, это может быть решением, но попробуйте что-нибудь еще раньше. Поэтому, пожалуйста, попробуйте передать файловый дескриптор вашего сокета конструктору glib.IOChannel, как я уже сказал. Это должно работать, и здесь есть пример (без использования сокетов): blocks-when-printing-la" title="pygtk асинхронный вывод, реализованный с помощью io add watch blocks при печати la">stackoverflow.com/questions/19294929/ - person liberforce; 15.11.2017
comment
Привет. Извините за мое отсутствие. Мне удалось передать сокет в gio.Channel() вот так fd = conn.fileno(). Спасибо! - person Morasiu; 16.11.2017
comment
Конечно. Я решил использовать Subprocess.Popen, но ваша идея тоже была отличной. Я владею тобой. - person Morasiu; 21.11.2017