2

我在获取 python 文档中显示的用于日志记录 DatagramHandler 的示例代码时遇到问题,下面显示的代码在收到的每个数据报上都给出了 EOFError 异常。

import socket
import logging
import cPickle
import struct
import sys

sock = socket.socket (socket.AF_INET, socket.SOCK_DGRAM)
sock.bind (('localhost', 9000))

handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter("UDP LogViewer %(asctime)s %(message)s"))
logger = logging.getLogger("Test")
logger.addHandler(handler)

try:
    while True:
        dgram_size = sock.recv(4)
        if len(dgram_size) < 4:
            break
        slen = struct.unpack(">L", dgram_size)[0]
        data = sock.recv(slen)

        while len(data) < slen:
            data = data + sock.recv(slen - len(data))

        try:
            obj = cPickle.loads(data)
            record = logging.makeLogRecord(obj)
            logger.handle(record)
        except:
            print "exception", sys.exc_info()[0]



finally:
    sock.close()

但是这段代码有效,任何想法

data, address = sock.recvfrom(8192)
rec = logging.makeLogRecord(cPickle.loads(data[4:]))
logger.handle(rec)

问候

4

2 回答 2

3

我希望您的第一次recv(4)调用会从数据报中复制前四个字节,然后将数据包的其余部分扔到地板上;您对 then 的第二次调用recv找不到任何可读取的内容并返回 EOFError。从我系统的udp(7)手册页:

   All receive operations return only one packet.  When the packet
   is smaller than the passed buffer, only that much data is
   returned; when it is bigger, the packet is truncated and the
   MSG_TRUNC flag is set.  MSG_WAITALL is not supported.

尝试读入整个数据报,从前四个字节中获取长度,然后处理存储整个数据报的数组子集。

当然,如果您的泡菜不完全适合连接的MTU,它可能永远不会按您的意愿工作。

于 2010-12-09T11:52:20.153 回答
0

一个完整的 MWA 看起来像这样。

请注意,我们只是丢弃了前四个字节(pickle-data 的大小),这些字节的存在是因为DatagramHandlerinherits SocketHandler,它在 TCP 模式下运行。由于我们在 UDP 上,我们可以读到数据包的末尾。正如 Sarnold 指出的那样,如果数据不适合数据包,我们需要一个更好的解决方案,而且由于 UDP 可能会丢失数据包,这将需要服务器端的定制。也许最简单的服务器端解决方案就是拆分任何消息,这样我们一开始就不会超过限制!

import socketserver
import socket
import pickle
import logging

class MyDatagramRequestHandler( socketserver.DatagramRequestHandler ):
    def handle( self ):
        try:
            while True:
                chunk = self.socket.recv( 2048 )
                chunk = chunk[4:]
                obj = self.unPickle( chunk )
                record = logging.makeLogRecord( obj )
                self.on_handle( record )
        except socket.timeout:
            pass

    def unPickle( self, data ):
        return pickle.loads( data )
        
    def on_handle( self, record: logging.LogRecord ):
        # do something, e.g.
        logger = logging.getLogger( record.name )
        logger.handle( record )

改编自https://docs.python.org/3/howto/logging-cookbook.html#logging-cookbook上的 TCP 示例。

于 2020-09-16T11:14:23.747 回答