dpkt源代码文档项目

时间:2014-05-22 15:42:18

标签: python networking rtp

Dpkt是一个python包创建和解析库https://code.google.com/p/dpkt/ 该项目缺乏初学者的文档。我正在尝试记录它并为所有人制作示例示例代码。根据我对python的了解,我很难理解一些源代码。这里例如是python RTP(实时传输协议)模块

https://code.google.com/p/dpkt/source/browse/trunk/dpkt/rtp.py#rtp.py源代码

# $Id$

"""Real-Time Transport Protocol"""

from dpkt import Packet

# version 1100 0000 0000 0000 ! 0xC000  14
# p       0010 0000 0000 0000 ! 0x2000  13
# x       0001 0000 0000 0000 ! 0x1000  12
# cc      0000 1111 0000 0000 ! 0x0F00   8
# m       0000 0000 1000 0000 ! 0x0080   7
# pt      0000 0000 0111 1111 ! 0x007F   0
#

_VERSION_MASK= 0xC000
_P_MASK     = 0x2000
_X_MASK     = 0x1000
_CC_MASK    = 0x0F00
_M_MASK     = 0x0080
_PT_MASK    = 0x007F
_VERSION_SHIFT=14
_P_SHIFT    = 13
_X_SHIFT    = 12
_CC_SHIFT   = 8
_M_SHIFT    = 7
_PT_SHIFT   = 0

VERSION = 2

class RTP(Packet):
    __hdr__ = (
        ('_type', 'H',      0x8000),
        ('seq',     'H',    0),
        ('ts',      'I',    0),
        ('ssrc',    'I',    0),
    )
    csrc = ''

    def _get_version(self): return (self._type&_VERSION_MASK)>>_VERSION_SHIFT
    def _set_version(self, ver):
        self._type = (ver << _VERSION_SHIFT) | (self._type & ~_VERSION_MASK)
    def _get_p(self): return (self._type & _P_MASK) >> _P_SHIFT
    def _set_p(self, p): self._type = (p << _P_SHIFT) | (self._type & ~_P_MASK)
    def _get_x(self): return (self._type & _X_MASK) >> _X_SHIFT
    def _set_x(self, x): self._type = (x << _X_SHIFT) | (self._type & ~_X_MASK)
    def _get_cc(self): return (self._type & _CC_MASK) >> _CC_SHIFT
    def _set_cc(self, cc): self._type = (cc<<_CC_SHIFT)|(self._type&~_CC_MASK)
    def _get_m(self): return (self._type & _M_MASK) >> _M_SHIFT
    def _set_m(self, m): self._type = (m << _M_SHIFT) | (self._type & ~_M_MASK)
    def _get_pt(self): return (self._type & _PT_MASK) >> _PT_SHIFT
    def _set_pt(self, m): self._type = (m << _PT_SHIFT)|(self._type&~_PT_MASK)

    version = property(_get_version, _set_version)
    p = property(_get_p, _set_p)
    x = property(_get_x, _set_x)
    cc = property(_get_cc, _set_cc)
    m = property(_get_m, _set_m)
    pt = property(_get_pt, _set_pt)

    def __len__(self):
        return self.__hdr_len__ + len(self.csrc) + len(self.data)

    def __str__(self):
        return self.pack_hdr() + self.csrc + str(self.data)

    def unpack(self, buf):
        super(RTP, self).unpack(buf)
        self.csrc = buf[self.__hdr_len__:self.__hdr_len__ + self.cc * 4]
        self.data = buf[self.__hdr_len__ + self.cc * 4:]

使用此代码,我能够在IPython Shell中执行以下操作

[37] import dpkt
[38] rtp_pkt=dpkt.rtp.RTP()
[39] rtp_pkt.pack_hdr()
Out[39]: '\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

[47] rtp_pkt.data="HelloWorld"
[48] rtp_pkt.pack()
Out[48]: '\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00HelloWorld'

基于我对Python中的类的理解,我在rtp.py中没有看到类中的“ init ”函数?我想知道上面的Ipython Shell命令是如何工作的?为什么rtp.py中的hdr变量以双下划线“__”开头,为什么每个类方法都以单下划线“_”开头。我知道这可能是私有或半私有但是它必须是那样吗?

我知道RTP类派生自Packet,为方便起见,它的源代码也粘贴在这里。

# $Id$

"""Simple packet creation and parsing."""

import copy, itertools, socket, struct

class Error(Exception): pass
class UnpackError(Error): pass
class NeedData(UnpackError): pass
class PackError(Error): pass

class _MetaPacket(type):
    def __new__(cls, clsname, clsbases, clsdict):
        t = type.__new__(cls, clsname, clsbases, clsdict)
        st = getattr(t, '__hdr__', None)
        if st is not None:
            # XXX - __slots__ only created in __new__()
            clsdict['__slots__'] = [ x[0] for x in st ] + [ 'data' ]
            t = type.__new__(cls, clsname, clsbases, clsdict)
            t.__hdr_fields__ = [ x[0] for x in st ]
            t.__hdr_fmt__ = getattr(t, '__byte_order__', '>') + \
                            ''.join([ x[1] for x in st ])
            t.__hdr_len__ = struct.calcsize(t.__hdr_fmt__)
            t.__hdr_defaults__ = dict(zip(
                t.__hdr_fields__, [ x[2] for x in st ]))
        return t

class Packet(object):
    """Base packet class, with metaclass magic to generate members from
    self.__hdr__.

    __hdr__ should be defined as a list of (name, structfmt, default) tuples
    __byte_order__ can be set to override the default ('>')

    Example::

    >>> class Foo(Packet):
    ...   __hdr__ = (('foo', 'I', 1), ('bar', 'H', 2), ('baz', '4s', 'quux'))
    ...
    >>> foo = Foo(bar=3)
    >>> foo
    Foo(bar=3)
    >>> str(foo)
    '\x00\x00\x00\x01\x00\x03quux'
    >>> foo.bar
    3
    >>> foo.baz
    'quux'
    >>> foo.foo = 7
    >>> foo.baz = 'whee'
    >>> foo
    Foo(baz='whee', foo=7, bar=3)
    >>> Foo('hello, world!')
    Foo(baz=' wor', foo=1751477356L, bar=28460, data='ld!')
    """
    __metaclass__ = _MetaPacket

    def __init__(self, *args, **kwargs):
        """Packet constructor with ([buf], [field=val,...]) prototype.

        Arguments:

        buf -- optional packet buffer to unpack

        Optional keyword arguments correspond to members to set
        (matching fields in self.__hdr__, or 'data').
        """
        self.data = ''
        if args:
            try:
                self.unpack(args[0])
            except struct.error:
                if len(args[0]) < self.__hdr_len__:
                    raise NeedData
                raise UnpackError('invalid %s: %r' %
                                  (self.__class__.__name__, args[0]))
        else:
            for k in self.__hdr_fields__:
                setattr(self, k, copy.copy(self.__hdr_defaults__[k]))
            for k, v in kwargs.iteritems():
                setattr(self, k, v)

    def __len__(self):
        return self.__hdr_len__ + len(self.data)

    def __getitem__(self, k):
        try: return getattr(self, k)
        except AttributeError: raise KeyError

    def __repr__(self):
        l = [ '%s=%r' % (k, getattr(self, k))
              for k in self.__hdr_defaults__
              if getattr(self, k) != self.__hdr_defaults__[k] ]
        if self.data:
            l.append('data=%r' % self.data)
        return '%s(%s)' % (self.__class__.__name__, ', '.join(l))

    def __str__(self):
        return self.pack_hdr() + str(self.data)

    def pack_hdr(self):
        """Return packed header string."""
        try:
            return struct.pack(self.__hdr_fmt__,
                            *[ getattr(self, k) for k in self.__hdr_fields__ ])
        except struct.error:
            vals = []
            for k in self.__hdr_fields__:
                v = getattr(self, k)
                if isinstance(v, tuple):
                    vals.extend(v)
                else:
                    vals.append(v)
            try:
                return struct.pack(self.__hdr_fmt__, *vals)
            except struct.error, e:
                raise PackError(str(e))

    def pack(self):
        """Return packed header + self.data string."""
        return str(self)

    def unpack(self, buf):
        """Unpack packet header fields from buf, and set self.data."""
        for k, v in itertools.izip(self.__hdr_fields__,
            struct.unpack(self.__hdr_fmt__, buf[:self.__hdr_len__])):
            setattr(self, k, v)
        self.data = buf[self.__hdr_len__:]

# XXX - ''.join([(len(`chr(x)`)==3) and chr(x) or '.' for x in range(256)])
__vis_filter = """................................ !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[.]^_`abcdefghijklmnopqrstuvwxyz{|}~................................................................................................................................."""

def hexdump(buf, length=16):
    """Return a hexdump output string of the given buffer."""
    n = 0
    res = []
    while buf:
        line, buf = buf[:length], buf[length:]
        hexa = ' '.join(['%02x' % ord(x) for x in line])
        line = line.translate(__vis_filter)
        res.append('  %04d:  %-*s %s' % (n, length * 3, hexa, line))
        n += length
    return '\n'.join(res)

try:
    import dnet
    def in_cksum_add(s, buf):
        return dnet.ip_cksum_add(buf, s)
    def in_cksum_done(s):
        return socket.ntohs(dnet.ip_cksum_carry(s))
except ImportError:
    import array
    def in_cksum_add(s, buf):
        n = len(buf)
        cnt = (n / 2) * 2
        a = array.array('H', buf[:cnt])
        if cnt != n:
            a.append(struct.unpack('H', buf[-1] + '\x00')[0])
        return s + sum(a)
    def in_cksum_done(s):
        s = (s >> 16) + (s & 0xffff)
        s += (s >> 16)
        return socket.ntohs(~s & 0xffff)

def in_cksum(buf):
    """Return computed Internet checksum."""
    return in_cksum_done(in_cksum_add(0, buf))

问题是如何真正理解源代码以使其文档正确完成?

0 个答案:

没有答案