我需要建议我应该使用 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% 的时间内都能正常工作然后严重故障的程序,但只有一次在蓝色月亮中——这种情况可能很难调试,因为您最终会花费数小时或数天来重现错误,更不用说诊断和修复它了。
我正在构建一个直播无线电流媒体,我想知道我应该如何处理多个连接。现在根据我的经验 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% 的时间内都能正常工作然后严重故障的程序,但只有一次在蓝色月亮中——这种情况可能很难调试,因为您最终会花费数小时或数天来重现错误,更不用说诊断和修复它了。