我需要建议我应该使用 select 还是线程?

I need advice should I use select or threading?

我正在构建一个直播无线电流媒体,我想知道我应该如何处理多个连接。现在根据我的经验 select 将阻止音频流式传输。它只播放 3 秒然后停止播放。我将举例说明我的意思。

import socket, select

headers = """
HTTP/1.0 200 OK\n
Content-Type: audio/mpeg\n
Connection: keep-alive\n
\n\n
"""
file="/path/to/file.mp3"
bufsize=4096 # actually have no idea what this should be but python-shout uses this amount
sock = socket.socket()
cons = list()
buf = 0
nbuf = 0

def runMe():
    cons.append(sock)
    file = open(file)
    nbuf = file.read(bufsize) # current buffer
    while True:
        buf = nbuf
        nbuf = file.read(bufsize)
        if len(buf) == 0:
           break
        rl, wl, xl = select.select(cons, [], [], 0.2)
        for s in rl:
            if s == sock:
                  con, addr = s.accept()
                  con.setblocking(0)
                  cons.append(con)
                  con.send(header)
             else:
                  data = s.recv(1024)
                  if not data:
                     s.close()
                     cons.remove(s)
                  else:
                     s.send(buf)

这是我如何使用 select 的示例。但是,这首歌不会一直播放。但是,如果我在 select 循环之外发送,它会播放,但会在第二次连接时死掉。我应该使用线程吗?

That is an example of how i'd use select. But, the song will not play all the way. But if I send outside the select loop it'll play but it'll die on a 2nd connection. Should I use threading?

您可以采用任何一种方式,但如果您的 select 实现无法正常工作,那是因为您的代码不正确,而不是因为基于 select 的实现无法完成这项工作——我认为多线程解决方案不会比基于 select 的解决方案更容易获得正确的解决方案。

无论您选择哪种实施方式,您都必须考虑的一个问题是 timing/throughput。您希望您的程序以与播放时大致相同的速率发送音频数据,还是希望以客户端愿意读取的速度发送音频数据,并将其留给客户端以适当的速度读取数据?请记住,每个 TCP 流的发送速率将不同,这取决于客户端选择接收信息的速度,以及服务器和客户端之间的网络路径的性能。

接下来要处理的下一个问题是客户端速度慢的问题——当其中一个 TCP 连接非常慢时,您希望您的程序做什么,例如由于网络拥塞?现在你的代码只是盲目地在所有套接字上调用 send() 而没有检查 return 值,这(假设套接字是非阻塞的)意味着如果给定套接字的输出缓冲区已满,那么一些(可能许多)字节的文件将被丢弃——也许这对你的目的来说没问题,我不知道。客户能否使用缺少任意部分的 mp3 数据流?我想那个客户 运行 充其量只会听到小故障。

撇开实施问题不谈,如果是我,我更喜欢 single-threaded/select() 方法,因为它更容易测试和验证。任何一种方法都需要做一些事情才能正确,但是对于单线程,您的程序的行为更具确定性——它要么工作正常,要么不工作,运行 给定的测试通常会给出每次结果相同(假设网络条件一致)。在一个多线程程序中,OTOH,线程的调度是不确定的,这使得很容易得到一个在 99.99% 的时间内都能正常工作然后严重故障的程序,但只有一次在蓝色月亮中——这种情况可能很难调试,因为您最终会花费数小时或数天来重现错误,更不用说诊断和修复它了。