Функция connect
определяет функцию, называемую xloop
, но она не вызывает эту функцию или не возвращает ее или не хранит ее где-нибудь, чтобы кто-либо еще ее вызывал. Вам нужно вызвать эту функцию, чтобы она ничего не делала.
Конечно, если вы просто вызываете его напрямую в строке, он будет работать вечно, то есть вы никогда не вернетесь в цикл событий, и пользовательский интерфейс зависнет и перестанет отвечать на пользователя.
Для этого есть два варианта: нарезание резьбы или опрос.
Очевидный способ сделать это с помощью a background thread. Основная идея очень проста:
def connect(self):
def xloop():
while 1:
data=clientsock.recv(buffer).decode()
print(data)
self.add(data)
self.t = threading.Thread(target=xloop)
self.t.start()
Однако есть две проблемы с этим.
Во-первых, нет способа остановить фоновый поток. Когда вы попытаетесь выйти из программы, он будет ждать остановки фонового потока, что означает, что он будет ждать вечно.
Это простое решение для этого: если вы сделаете его «потоком демона», он будет уничтожен, когда основная программа выйдет. Это явно не подходит для потоков, которые выполняют работу, которая может быть повреждена, если она прерывается посередине, но в вашем случае это не похоже на проблему.Таким образом, просто изменить одну строку:
self.t = threading.Thread(target=xloop, daemon=True)
Во-вторых, что self.add
метод должен изменить Tkinter виджет. Вы не можете сделать это из фонового потока. В зависимости от вашей платформы, он может терпеть неудачу молча, поднимать исключение или даже сбой - или, что еще хуже, он может работать 99% времени и сбой 1%.
Итак, вам нужно как-то отправить сообщение в основной поток, запросив его, чтобы сделать модификацию виджета для вас. Это немного сложно, но Tkinter and Threads объясняет, как это сделать.
В качестве альтернативы вы можете использовать mtTkinter
, который перехватывает вызовы Tkinter в фоновом потоке и автоматически передает их в основной поток, поэтому вам не нужно беспокоиться об этом.
Другой вариант заключается в изменении блокировки xloop
функцию в функцию неблокируемой, что опросы для данных. Проблема в том, что вы хотите ждать на событиях TKinter GUI, но вы также хотите дождаться сокета.
Если вы могли бы интегрировать сокет в основной цикл событий, это было бы легко: новое входящее сообщение обрабатывалось точно так же, как и любое другое событие. Некоторые из более мощных графических интерфейсов, таких как Qt, дают вам способы сделать это, но Tkinter этого не делает. Рамка реактора, такая как Twisted, может завязать себя в Tkinter и добавить ее для вас (или, по крайней мере, подделать красиво). Но если вы хотите придерживаться своего основного дизайна, вы должны сделать это сами.
Итак, есть два варианта:
- Дает Tkinter полного контроля. Попросите его называть вашу функцию каждый, скажем, 1/20 секунды, а в функции выполняет неблокирующую проверку. Или, может быть, цикл вокруг неблокирующих проверок, пока нечего читать.
- Дайте управление гнездом. Попросите Tkinter вызывать вашу функцию каждый раз, когда она получает шанс, и блокировать 1/20 секунд проверки данных перед возвратом в Tkinter.
Конечно 1/20 секунды не может быть правильная длина для многих приложений, не ответа не совсем правильно. Во всяком случае, вот простой пример:
def poll_socket(self):
r, w, x = select.select([clientsock], [], [], 0)
if r:
data=clientsock.recv(buffer).decode()
print(data)
self.add(data)
self.after(50, self.poll_socket)
def connect(self):
self.after(50, self.poll_socket)
В качестве побочного примечания есть серьезная проблема с этим кодом - и, вероятно, с сервером. [TCP - поток байтов] (http://stupidpythonideas.blogspot.com/2013/05/sockets-are-byte-streams-not-message.html); буфер, отправленный 'send', всегда может отображаться как два отдельных вызова' recv'. И если кодировка по умолчанию является чем-то многобайтным, например UTF-8, это означает, что вы можете получить половину символа, а затем этот 'decode' будет повышаться. Первая часть редко встречается на локальном хосте, а вторая вы должны получить довольно неудачный ... что означает, что это сломается, когда это действительно нужно работать, но будет больно воспроизводить и отлаживать. – abarnert
Как еще одно примечание, имеющее кучу глобальных переменных, к которым обращается экземпляр 'ipbcc', очень странный дизайн. Он делает 'ipbcc' то, что не является одиночным, но потерпит неудачу, если вы не притворитесь, что это ... Вероятно, лучше сделать' customersock' членом. – abarnert