Python日志数据报处理器
我在使用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)
祝好
2 个回答
0
一个完整的MWA(消息写入适配器)看起来大概是这样的。
注意,我们直接忽略了前四个字节(这部分是pickle数据的大小),这些字节存在是因为DatagramHandler
是从SocketHandler
继承过来的,而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 )
这个内容改编自TCP示例,详细信息可以查看https://docs.python.org/3/howto/logging-cookbook.html#logging-cookbook。
3
我想你第一次调用 recv(4)
的时候,会把数据包的前四个字节复制出来,然后把剩下的部分丢掉。接着你第二次调用 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),那可能就永远无法按你想的那样工作了。