【问题标题】:How can I send messages to multiple twitch channels using python 3 Select()?如何使用 python 3 Select() 将消息发送到多个抽搐频道?
【发布时间】:2019-05-11 01:00:12
【问题描述】:

我正在尝试在 Python 3 中创建一个 Twitch 机器人,该机器人将同时监控并向多个频道发送消息。我已经用线程做到了这一点,但它显然对 CPU 要求很高,而且我读过使用 Select() 更有效。下面的代码允许我从多个抽搐频道读取聊天内容,但我不知道如何确定返回为可写的连接是否是我想要写入的连接。

我可以传入具有套接字连接和标识符的对象列表,以便我知道哪些对象作为可写返回?

我已经阅读了许多与使用 select() 以及其他在线资源相关的 stackoverflow 帖子,但是,作为一个业余编码员,我很难理解这一点。

#!/usr/bin/env

import socket
import select

HOST = "irc.chat.twitch.tv"
PORT = 6667
NICK = "channelname"
PASS = 'oauth:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
CHANNEL = "channelname"


def create_sockets(usr_list):
    final_socket_list = []
    channels_first_element = 0
    channels_last_element = len(usr_list)
    for index in range(channels_first_element, channels_last_element):
        channel = usr_list[index]
        s = socket.socket()
        s.connect((HOST, PORT))
        s.setblocking(False)
        s.send(bytes("PASS " + PASS + "\r\n", "UTF-8"))
        s.send(bytes("NICK " + NICK + "\r\n", "UTF-8"))
        s.send(bytes("JOIN #" + channel + " \r\n", "UTF-8"))
        s.send(bytes('CAP REQ :twitch.tv/membership\r\n'.encode('utf-8')))
        s.send(bytes('CAP REQ :twitch.tv/commands\r\n'.encode('utf-8')))
        s.send(bytes('CAP REQ :twitch.tv/tags\r\n'.encode('utf-8')))
        final_socket_list.append(s)
    return final_socket_list


def main():
    alive = True
    user_list = ['channelone', 'channeltwo', 'channelthree']
    user_sockets = create_sockets(user_list)

    while alive:
        readable, writable, errorreads = select.select(user_sockets, user_sockets, [])
        if len(readable) != 0:
            for element in readable:
                print(str(element.recv(1024), "utf-8"))

if __name__ == "__main__":
    main()

【问题讨论】:

    标签: python-3.x sockets select irc twitch


    【解决方案1】:

    首先要指出的是select() 的参数是为了告诉select() 何时返回——也就是说,通过在 first/read_fds 参数中包含一个套接字,你告诉select() 返回为一旦该套接字具有可以读取的传入数据,并通过在第二个/write_fds 参数中包含一个套接字,您就告诉select() 在该套接字具有缓冲区空间准备就绪后立即返回写到。

    因此,如果您有数据要尽快发送到该套接字,则仅在select() 的第二个/write_fds 参数中包含一个套接字很重要(如果您想提高 CPU 效率)是该套接字的传出数据缓冲区中的可用空间。如果您总是将所有套接字传递给 write_fds 参数(正如您当前在发布的代码中所做的那样),那么 select() 几乎总是会立即返回(因为套接字通常几乎总是有缓冲区空间可用于写入),你最终会以接近 100% 的使用率旋转 CPU,这是非常低效的。

    请注意,对于使用阻塞 TCP 套接字的轻型服务器,只要始终将 [] 作为第二个参数传递给 select(),通常就足够了,前提是您永远不会真正填充任何套接字的传出 -数据缓冲区(如果你这样做了,那么在该套接字上的下一个 send() 调用将简单地阻塞,直到有可用的缓冲区空间,这没关系)。如果你想使用非阻塞套接字,你可以做一个简单的假设,即没有套接字的传出数据缓冲区会变满(在这种情况下将[] 传递给 write_fds 参数很好),或者是 100%健壮,您需要包含自己的每个套接字传出数据 FIFO 队列,并且仅当其 FIFO 队列非空且套接字指示它已准备好写入时,才将每个套接字包含在 write_fds 参数中, send() 尽可能多的来自套接字 FIFO 队列头部的字节。

    至于您要写入哪些套接字,这将完全取决于您的应用程序试图做什么,并且可能不取决于哪些套接字被选为可写。大多数程序都包含一个Dictionary(或其他类似的查找机制),用于快速确定哪个数据对象对应于给定的套接字,因此当一个套接字select()'s 准备好读取时,您可以找出哪个数据对象来自该套接字的数据应被视为“来自”。然后,您可以写入任何需要写入的套接字作为响应。

    【讨论】:

    • 感谢您的详细回复。我得消化一下。 :)
    猜你喜欢
    • 1970-01-01
    • 2019-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-31
    • 1970-01-01
    • 2021-06-11
    • 2020-11-16
    相关资源
    最近更新 更多