如何修复 python 中的 sock.recv() 阻塞状态

How to fix sock.recv() blocking state in python

我在 python 中是网络编程的新手。 我使用我在互联网上找到的连接到多播地址并接收 MPEG-TS 数据包的脚本。我在 wireshark 上看到,在 sock.setsockopt 命令之后,MPEG-TS 数据包正在到达我的计算机。

来自 wireshark 的屏幕
https://imgur.com/XJDwd61

但是当我想打印 sock.recv() 结果时出现问题。如果我正确理解文档,我相信这是因为阻塞状态。取消注释 setblocking(0) 后出现 10035 错误。 您知道我需要添加什么才能在终端中打印收到的数据吗? 提前谢谢你。

我尝试将 sock.recv() 中的 buffer_size 更改为更小、相等以及现在的状态 - 超过 1358 字节,这是单个数据报字节的数量。

    import socket
    import struct
    import time

    MCAST_GRP = '239.0.1.104'
    MCAST_PORT = 12345
    IS_ALL_GROUPS = True


    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    if IS_ALL_GROUPS:
        # on this port, receives ALL multicast groups
        sock.bind(('', MCAST_PORT))
    else:
        # on this port, listen ONLY to MCAST_GRP
        sock.bind((MCAST_GRP, MCAST_PORT))

    mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)

    sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)

    #sock.setblocking(0)
    print(f"Entering while loop")
    while True:
        time.sleep(1)
        print(f"I'm in while loop")    
        print(sock.recv(4096))

试试这个简单的代码,如果你愿意,你可以少设置BUFF_SIZE。

#BUFF_SIZE = 4096
BUFF_SIZE = 1024
data = b''
while True:
    #chunk = s.recv(BUFF_SIZE)

    #FOR UDP (@Saeed credits)
    chuck = sock.recvfrom(BUFF_SIZE)

    data += chunk
    if len(chunk) < BUFF_SIZE:
        break

print(data)

根据 How do you UDP multicast in Python? 中的示例代码,当我尝试在我的系统上 运行 它时,它工作正常。因此,我根据您的更改对其进行了更改,这是 receiver.py 代码,

import socket
import struct

MCAST_GRP = '239.0.1.104'
MCAST_PORT = 12345
IS_ALL_GROUPS = True

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if IS_ALL_GROUPS:
    # on this port, receives ALL multicast groups
    sock.bind(('', MCAST_PORT))
else:
    # on this port, listen ONLY to MCAST_GRP
    sock.bind((MCAST_GRP, MCAST_PORT))

mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)

sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)

print("Entering while loop")
while True:
    print("I'm in while loop")
    print(sock.recv(4096))

注意,我稍微修改了打印语句并删除了 f,因为它会生成错误。这是 sender.py 代码,

import socket

MCAST_GRP = '239.0.1.104'
MCAST_PORT = 12345
# regarding socket.IP_MULTICAST_TTL
# ---------------------------------
# for all packets sent, after two hops on the network the packet will not 
# be re-sent/broadcast (see https://www.tldp.org/HOWTO/Multicast-HOWTO-6.html)
MULTICAST_TTL = 2

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, MULTICAST_TTL)
sock.sendto(bytes("robot", 'UTF-8'), (MCAST_GRP, MCAST_PORT))

请注意,我正在将 robot 字符串转换为使用 UTF-8 编码的字节,因为如果使用 python3 这是必需的,而在 python2 中则不是必需的。这是我的执行结果,

如您所见,当我调用发送方时,接收方会显示 robot 字符串并循环执行 while 循环。它工作正常。

在这种情况下,如果您已经收到在 Wireshark 上显示的多播数据包,则需要确保这些数据包被发送到您正在侦听的相同端口号,即 12345 在你的情况下。如果它们被发送到不同的端口号[可能是这种情况],那么请更改您的接收器以侦听该端口号以开始接收这些数据包。