龙卷风从组播组接收UDP数据包

时间:2018-06-21 07:53:16

标签: asynchronous tornado multicast

我有一台服务器,我想从该服务器接收多播组的数据。我可以使用任何内置功能来接收此多播UDP数据包吗?

编辑:代码实现
我已经实现了代码,如下所示:

#!/usr/bin/env python

import socket
import struct
import os
import errno
import binascii
import tornado.ioloop
from tornado.ioloop import IOLoop
from tornado.platform.auto import set_close_exec

class UDPHandler():
    """ 
    Connect to multicast group 
    """
    def __init__(self, ip, port, io_loop):
        self.io_loop    = io_loop
        self._multiIP   = ip
        self.port       = port
        self._sock      = None
        self._socket    = {} # fd -> socket object

    def conn(self):
        """
        Listner to multicast group
        """
        self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self._sock.settimeout(3)
        self._sock.bind(('', self.port))
        self._sock.setblocking(0)
        group   = socket.inet_aton(self._multiIP)
        mreq    = struct.pack('4sL', group, socket.INADDR_ANY)
        self._sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
        self._socket[self._sock.fileno()] = self._sock
        print("self._sock:", self._sock)

    def onRx(self, data, addr):
        print("addr, data:", addr, len(str(data)))
        print(data)

    def r(self):
        self.conn()
        add_socket_handler(self._sock, self.onRx, self.io_loop)

def add_socket_handler(sock, callback, io_loop):
    def accept_handler(fd, events):
        while True:
            try:
                data, address = sock.recvfrom(1024)
            except socket.error as e:
                if e.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN):
                    callback(None, None)
            except Exception as e:
                print("except:", e)
                callback(None, None)

            callback(data, address)
    io_loop.add_handler(sock.fileno(), accept_handler, IOLoop.READ)

def periodic():
    # print("periodic")
    None
def main():
    MULTICAST_IP = "224.1.1.10"
    RECEIVE_PORT = 10003
    udpRx = UDPHandler(MULTICAST_IP, RECEIVE_PORT, tornado.ioloop.IOLoop.current())
    udpRx.r()
    tornado.ioloop.PeriodicCallback(periodic, 1000).start()
    tornado.ioloop.IOLoop.current().start()

if __name__ == "__main__":
    main()

现在的问题是即使我收到一个数据包,我也会一次又一次地收到相同的数据包,这是在循环中获得相同的数据包。代码有问题吗?尤其是add_socket_handler吗?

编辑2:
我在add_socket_handler中的while循环中添加了一个break语句,现在看来运行良好。

def add_socket_handler(sock, callback, io_loop):
    def accept_handler(fd, events):
        while True:
            try:
                data, address = sock.recvfrom(1024)
                callback(data, address)
            except socket.error as e:
                if e.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN):
                    raise
            except Exception as e:
                raise
            break ## change in here
    io_loop.add_handler(sock.fileno(), accept_handler, io_loop.READ)

这应该是怎么做的?

1 个答案:

答案 0 :(得分:0)

您的break中的add_socket_handler向后看。您想要循环直到获得EWOULDBLOCK / EAGAIN。 (在中断写入后,它仍然可以工作,但是效率稍低,可能会丢失数据包)。

def add_socket_handler(sock, callback, io_loop):
    def read_handler(fd, events):
        while True:
            try:
                data, address = sock.recvfrom(1024)
                callback(data, address):
            except socket.error as e:
                if e.errno in (errno.EWOULDBLOCK, errno.EAGAIN):
                    return
                raise
    io_loop.add_handler(sock, read_handler, io_loop.READ)

除此之外,这看起来不错,尽管我自己还没有使用多播UDP。