【问题标题】:Tornado receive UDP packets from multicast groupTornado 接收来自多播组的 UDP 数据包
【发布时间】:2018-06-29 22:22:43
【问题描述】:

我有一台服务器,我想从多播组接收数据。是否有任何内置函数可用于接收此多播 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)

这是应该怎么做的吗?

【问题讨论】:

标签: asynchronous tornado multicast


【解决方案1】:

add_socket_handler 中的 break 向后看。你想循环直到你得到 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。

【讨论】:

  • 假设我想接收一个恒定长度为 1024 的数据包。在这种情况下是否需要进行循环,或者如果我只说 sock.recvfrom(1024) 而没有任何循环会更好吗?跨度>
  • 我相信它可以在没有循环的情况下工作,但如果您快速接收数据包,它会稍微更有效。
  • 我正在快速接收数据包并且数据包的长度是恒定的。所以我想到了使用无循环。
猜你喜欢
  • 2022-11-02
  • 2019-05-31
  • 2012-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-23
  • 2011-03-02
  • 1970-01-01
相关资源
最近更新 更多