#python #multithreading #sockets #websocket #twitch
Вопрос:
Я пытаюсь найти действительно беспокойные чаты twitch для ключевых слов, но иногда сокет останавливается на долю секунды, но за эту долю секунды может пройти 5 сообщений. Я думал о реализации некоторой многопоточности, но в приведенном ниже коде не повезло. Похоже, что все они не могут поймать ключевое слово или все преуспевают. Любая помощь будет признательна. Код ниже:
import os import time from dotenv import load_dotenv import socket import logging from emoji import demojize import threading # loading environment variables load_dotenv() # variables for socket server = "irc.chat.twitch.tv" port = 6667 nickname = "frankied003" token = os.getenv("TWITCH_TOKEN") channel = "#xqcow" # creating the socket and connecting sock = socket.socket() sock.connect((server, port)) sock.send(f"PASS {token}n".encode("utf-8")) sock.send(f"NICK {nickname}n".encode("utf-8")) sock.send(f"JOIN {channel}n".encode("utf-8")) while True: consoleInput = input( "Enter correct answer to the question (use a ',' for multiple answers):" ) # if console input is stop, the code will stop ofcourse lol if consoleInput == "stop": break # make array of all the correct answers correctAnswers = consoleInput.split(",") correctAnswers = [answer.strip().lower() for answer in correctAnswers] def threadingFunction(): correctAnswerFound = False # while the correct answer is not found, the chats will keep on printing while correctAnswerFound is not True: while True: try: resp = sock.recv(2048).decode( "utf-8" ) # sometimes this fails, hence retry until it succeeds except: continue break if resp.startswith("PING"): sock.send("PONGn".encode("utf-8")) elif len(resp) gt; 0: username = resp.split(":")[1].split("!")[0] message = resp.split(":")[2] strippedMessage = " ".join(message.split()) # once the answer is found, the chats will stop, correct answer is highlighted in green, and onto next question if str(strippedMessage).lower() in correctAnswers: print(bcolors.OKGREEN username " - " message bcolors.ENDC) correctAnswerFound = True else: if username == nickname: print(bcolors.OKCYAN username " - " message bcolors.ENDC) # else: # print(username " - " message) t1 = threading.Thread(target=threadingFunction) t2 = threading.Thread(target=threadingFunction) t3 = threading.Thread(target=threadingFunction) t1.start() time.sleep(.3) t2.start() time.sleep(.3) t3.start() time.sleep(.3) t1.join() t2.join() t3.join()
Ответ №1:
Во-первых, нет особого смысла позволять 3 потокам параллельно читать в одном и том же сокете, это приводит только к путанице и условиям гонки.
Основная проблема, однако, заключается в том, что вы предполагаете, что один recv
человек всегда будет читать одно сообщение. Но TCP работает не так. TCP не имеет понятия о сообщении, а представляет собой только поток байтов. Сообщение — это концепция прикладного уровня. Один recv
может содержать одно сообщение, несколько сообщений, части сообщений …
Таким образом, вы должны фактически проанализировать полученные данные в соответствии с семантикой, определенной протоколом приложения, т. е.
- инициализировать некоторый буфер
- получите некоторые данные из сокета и добавьте их в буфер — не декодируйте данные
- извлеките все полные сообщения из буфера, декодируйте и обработайте каждое сообщение отдельно
- оставьте оставшиеся неполные сообщения в буфере
- продолжайте с #2
Кроме того, не отбрасывайте слепо ошибки во recv(..).decode(..)
время . Учитывая, что вы используете блокирующий сокет recv
, обычно произойдет сбой только в том случае, если возникнет фатальная проблема с подключением, и в этом случае повторная попытка не поможет. Проблема, скорее всего, связана с тем, что вы вызываете decode
неполные сообщения, которые также могут означать недопустимую кодировку utf-8. Но поскольку вы просто игнорируете проблему, вы, по сути, теряете сообщения.
Комментарии:
1. Как вы узнаете, завершено сообщение или нет. У Twitch нет прикладного протокола или отличной документации по этому вопросу.
2. ААААА, я понял, ты был прав. Я принимал первое сообщение в каждом ответе, но ответов было несколько.