2016-06-08 2 views
1

Вот основная идея потоков, которые я создаю в моей программе:Добавление time.sleep в многопоточной программе решает UnicodeDecodeError в питона

Main thread 
     | 
    ListenerCreator(The WebSocketServer thread) ---> Several listener threads(using log()) 

Таким образом, основной поток создает ListenerCreator нить, которая соединяет для нескольких клиентов и создает поток слушателей для каждого клиента. Вот кратко, что происходит в потоке слушателя: EDIT1: Я использую WebSockets для чтения/записи данных с моего клиента. Для этого я создал свой собственный сервер. Существует framing protocol, который стандарт указывает - и я использую это. На стороне клиента я просто использую WebSocket.send() и «разоблачая» сообщения в соответствии с инструкциями, приведенными в протоколе (см. Раздел 5.3 в приведенной выше ссылке). я был бы готов предоставить код сервера, если кто-то просит его, однако, вот краткое описание:

class WebSocketServer: 
    def start(): 
      #Open server socket, bind to host:port 
      while True: 
       #Accept client socket, start a new listener thread for self.log(client) 
    def log(client): 
      #Receive data using socket.socket.recv(1024) 
      #Unmask data as per the protocol 
      #Decode using data.decode("utf-8") 
      #Append to data_q while holding data_q_lock 

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

Между тем в главном потоке:

while breaking!=len(client_list): 
     #time.sleep(0.5)  
     with data_q_lock: 
      for i in range(len(data_q)): 
       mes = data_q.pop() 
       for m in client_list: 
        if "#DONE"== mes: 
         breaking += 1 
       if(mes[:len("#COUNT:")] == "#COUNT:"): 
        print(mes) 

Поэтому в основном то, что делает этот цикл является: Петля через в data_q, если сообщение начинается с «#COUNT», напечатать сообщение, и после получения определенного количества из сообщений «#DONE», выйдите из цикла. Если time.sleep раскомментирован, тогда этот код работает, однако без time.sleep я получаю UnicodeDecodeError в log. Также я получаю ошибку иногда, иногда программа работает отлично. (Клиент посылает одни и те же данные каждый раз, между прочим) Итак, мой вопрос: почему требуется время. Я думал, что это что-то связано с GIL в python, так как time.sleep выпускает GIL. Однако даже после прочтения об этом я не мог решить вопрос

+0

Просьба показать, как вы читаете данные из сокета в слушателе, что очень важно для вашей проблемы :-) – donkopotamus

ответ

0

В настоящее время нет информации о том, как слушатель считывает данные с сокета. Кажется вероятным, однако, что это вызвано обычным недоразумением сокетов.

Данные, отправленные по розетке, не «обрамлены» каким-либо образом гнездом. Представьте, если бы я послал сообщение «привет» три раза по сокету. Тогда, как и запись в файл без разрывов строк, следующий будет течь на сокете:

hellohellohello 

Теперь рассмотрит читатель ... при чтении данных, как он знает, где одно сообщения («привет») начинается и далее? Он не может, если отправитель и получатель не согласятся о том, как эти данные должны быть «обрамлены». Это можно сделать, согласившись на какой-либо протокол, например:

  • данные об отказах; или
  • сообщения фиксированного размера; или
  • размер префиксные сообщения.

Это становится более сложным, конечно, даже когда вы решили, каким образом данные должны быть сформулированы, вы не можете гарантировать, что socket.recv возвратит «целый» сообщение ... он просто вернет все данные, случается, в буфере в то время. Это может быть половина сообщения или сообщение с половиной. Его задача - собрать данные, считываемые из сокета, и разделить их на сообщения.

Обращаясь к вашей проблеме, где вы отправляете данные utf-8. Как читатель знает, что он прочитал полное сообщение данных utf-8? Скорее всего, что происходит здесь, так это то, что вы получили только частичное сообщение ... еще впереди еще.

В частности, действительный символ utf-8 может состоять из более чем одного байта. Поэтому, если ваше частичное сообщение заканчивается в середине многобайтового utf-8 представления символа, тогда вы, конечно же, не сможете его декодировать.

+0

Спасибо! Я добавил дополнительную информацию о том, как я действительно использовал сокеты. Я использую сообщения с префиксом по размеру в соответствии с протоколом WebSocket. – user6397000

+0

То, что вы получаете 'UnicodeDecodeError', почти наверняка указывает на то, что ваша полезная нагрузка данных неполна ... попробуйте поймать эту ошибку и проверив фактический фрейм, чтобы убедиться, что это то, что вы думаете. (Я предполагаю, что вы понимаете, что 'socket.recv (1024)' может вернуть вам меньше 1024 байта?) – donkopotamus

Смежные вопросы