有没有办法不缓存UDP套接字的数据

2 投票
1 回答
2849 浏览
提问于 2025-04-18 07:44

我正在做一个服务器,它通过UDP发送时钟滴答的多播消息。服务器的代码是这样的:

import socket
import struct
import sys
import time

multicast_group = ('224.3.29.71', 10000)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(0.2)
ttl = struct.pack('B', 255)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)

try:
    i = 0
    while True:
        #print "tick"

        sent = sock.sendto(str(i), multicast_group)
        i += 1
        time.sleep(1.0/25.0)

finally:
    print "closing socket"
    sock.close()

我希望客户端在收到一个滴答时能做点事情,但在处理过程中跳过它错过的滴答。

举个例子,如果客户端收到滴答#1,但在处理时错过了滴答#2和#3,我希望下一个收到的消息是滴答#4。

不过,似乎因为套接字有缓冲,有时候它会收到那些应该跳过的滴答。

这是客户端的代码:

import socket
import struct
import sys
import time

multicast_group = '224.3.29.71'
server_address = ('', 10000)

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(server_address)
sock.setblocking(0)

group = socket.inet_aton(multicast_group)
mreq = struct.pack('4sL', group, socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)

while True:
    try:
        data, address = sock.recvfrom(1024)
        print data
        time.sleep(1) #simulate processing
    except socket.error:
        pass

客户端的输出: 1 2 3 4 5 ...

我该怎么做才能实现我想要的效果呢?

补充说明一下问题:每次客户端收到一个滴答时,我都会记录一个事件。我想记录的顺序是:[触发,暂停,触发,暂停],但由于一些滴答被缓冲,我得到的是:[触发,暂停,触发,触发,触发],这让我的事件时间间隔太近了。

1 个回答

3

套接字缓冲区是在操作系统的内核里面,而不是在Python里面。每当有数据包到达时,它会被放进这个缓冲区,直到用户空间从内核中读取它。你可以使用setsockopt来改变缓冲区的大小,但这个大小是以字节为单位,而不是以数据包为单位。如果把缓冲区设置得太小,就不太好,因为如果机器上收到一个数据包,而套接字缓冲区已经满了,新到的数据包就会被丢弃。

更好的方法是保持套接字缓冲区的默认设置,但把套接字设置为非阻塞模式,然后不断调用recvfrom,直到没有更多数据为止——然后处理你最后读取的数据包。

撰写回答