带C库的Python

2024-10-03 13:24:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我一直在研究python的开源代码,其中很多都在src中有一个目录,其中有.c和.h文件。在

例如,有一个名为protocol的目录,其中有.c和.h文件(这些.c文件有静态PyObject*)。在

如果我想导入这个目录以便使用这些函数,需要什么(或者如何从.py文件中使用这些.c文件)?在

我知道你需要init.py来导入一个目录,所以我这样做了,但是不知道如何从.c文件访问对象

例如,它们有一个python代码 arp = protocol.arp(shw, thw, sp, tp, constants.arp.ARPOP_REQUEST)

但是我不理解从.py到.c的转换,因为下面的文件(protocol/arp.c)没有名为arp的类(它有静态PyObject)* ARPObject_new(PyTypeObject*type,PyObject*args,PyObject*kwds)。有人能给我解释一下这个转变吗?在

#include "Python.h"
#include "structmember.h"
#define PROTOCOL_MODULE
#include "protocolmodule.h"

PyProtocol_newARPObjectFromPacket_RETURN PyProtocol_newARPObjectFromPacket PyProtocol_newARPObjectFromPacket_PROTO;
PyProtocol_injectARP_RETURN PyProtocol_injectARP PyProtocol_injectARP_PROTO;
PyProtocol_ARPCheck_RETURN PyProtocol_ARPCheck PyProtocol_ARPCheck_PROTO;

int PyProtocol_ARPCheck(PyObject *o)
{
    return ARPObject_Check(o);
}


/**************
*    ARP     *
**************/
ARPObject *
PyProtocol_newARPObjectFromPacket(arp_t *arp, int *parsed_length)
{
    ARPObject *self;
    char *packet = (char *) (arp + 1);
    struct in_addr ia;
    self = PyObject_New(ARPObject, &ARP_Type);
    if (self == NULL)
        return NULL;
    self->ar_hrd = ntohs(arp->ar_hrd);
    self->ar_pro = ntohs(arp->ar_pro);
    self->ar_hln = arp->ar_hln;
    self->ar_pln = arp->ar_pln;
    self->ar_op = ntohs(arp->ar_op);
    self->ar_spa = NULL;
    self->ar_tpa = NULL;
    self->ar_sha = NULL;
    self->ar_tha = NULL;
    self->data = NULL;

    if (self->ar_pro == ETHERTYPE_IP)
    {
        memcpy(&ia, packet + self->ar_hln, sizeof(ia));
        self->ar_spa = PyString_FromString(inet_ntoa(ia));
        memcpy(&ia, packet + (2 * self->ar_hln) + self->ar_pln, sizeof(ia));
        self->ar_tpa = PyString_FromString(inet_ntoa(ia));
    }
    else
    {
        PyErr_SetString(PyExc_NotImplementedError, "Only support decoding IPv4 ARP packets");
        return NULL;
    }

    if (self->ar_hrd == ARPHRD_ETHER)
    {
        self->ar_sha = MACasString(packet);
        self->ar_tha = MACasString(packet + self->ar_hln + self->ar_pln);
    }
    else
    {
        Py_XDECREF(self->ar_spa);
        Py_XDECREF(self->ar_tpa);
        PyErr_SetString(PyExc_NotImplementedError, "Only support decoding Ethernet ARP packets");
        return NULL;
    }

    self->data = PyString_FromStringAndSize((char *) arp, (sizeof(arp_t) + (2 * self->ar_hln) + (2 * self->ar_pln)));

    *parsed_length += (sizeof(arp_t) + (2 * self->ar_hln) + (2 * self->ar_pln));
    return self;
}

static PyObject *
ARPObject_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    static char *kwargs[] = {"sourcehardware", "targethardware",
        "sourceprotocol", "targetprotocol",
        "operation", NULL };
    PyObject *sourcehardware, *targethardware;
    PyObject *sourceprotocol, *targetprotocol;
    int operation;
    ARPObject *self;
    char *temp;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "SSSSi", kwargs, &sourcehardware, &targethardware,
                                     &sourceprotocol, &targetprotocol, &operation))
        return NULL;
    self = PyObject_New(ARPObject, &ARP_Type);
    if (! self)
        return NULL;

    temp = decodeMAC(sourcehardware);
    if (! temp)
    {
        PyErr_SetString(PyExc_TypeError, "Invalid format for source MAC address");
        return NULL;
    }
    else
        free(temp);

    temp = decodeMAC(targethardware);
    if (! temp)
    {
        PyErr_SetString(PyExc_TypeError, "Invalid format for destination MAC address");
        return NULL;
    }
    else
        free(temp);


    self->ar_hrd = ARPHRD_ETHER;
    self->ar_pro = ETHERTYPE_IP;
    self->ar_hln = ETHER_ADDR_LEN;
    self->ar_pln = 4;
    self->ar_op = operation;
    self->data = NULL;

    Py_INCREF(sourcehardware);
    Py_INCREF(targethardware);
    Py_INCREF(sourceprotocol);
    Py_INCREF(targetprotocol);
    self->ar_sha = sourcehardware;
    self->ar_tha = targethardware;
    self->ar_spa = sourceprotocol;
    self->ar_tpa = targetprotocol;

    return (PyObject *) self;
}

int
PyProtocol_injectARP(PyObject *arp_py, libnet_t *context)
{
    ARPObject *self = (ARPObject *) arp_py;
    char *sha = decodeMAC(self->ar_sha);
    char *tha = decodeMAC(self->ar_tha);
    struct in_addr spa, tpa;
    libnet_ptag_t r;
    inet_aton(PyString_AsString(self->ar_spa), &spa);
    inet_aton(PyString_AsString(self->ar_tpa), &tpa);
    r = libnet_build_arp(self->ar_hrd,
                         self->ar_pro,
                         self->ar_hln,
                         self->ar_pln,
                         self->ar_op,
                         sha,           // Source hardware address
                         (char *) &spa, // Target hardware address
                         tha,           // Source protocol address
                         (char *) &tpa, // Target protocol address
                         NULL,
                         0,
                         context,
                         0);
    free(sha);
    free(tha);

    if (r == -1)
    {
        PyErr_SetString(ErrorObject, libnet_geterror(context));
        return 0;
    }
    return 1;
}

static void
ARPObject_dealloc(ARPObject *self)
{
    Py_XDECREF(self->ar_sha);
    Py_XDECREF(self->ar_tha);
    Py_XDECREF(self->ar_spa);
    Py_XDECREF(self->ar_tpa);
    Py_XDECREF(self->data);
    PyObject_Del(self);
}

static PyObject *
ARPObject_str(ARPObject * self)
{
    PyObject *result = PyString_FromFormat("ARP(op=0x%04x, protocol=0x%04x, %s (%s) -> %s (%s))",
                                           self->ar_op, self->ar_pro,
                                           PyString_AsString(self->ar_sha),
                                           PyString_AsString(self->ar_spa),
                                           PyString_AsString(self->ar_tha),
                                           PyString_AsString(self->ar_tpa));
    return result;
}



static PyMethodDef ARPObject_methods[] =
{
    {NULL, NULL}
};

static PyMemberDef ARPObject_members[] =
{
    {"protocol", T_USHORT, offsetof(ARPObject, ar_pro), 0, "ARP requested protocol"},
    {"operation", T_USHORT, offsetof(ARPObject, ar_op), 0, "ARP operation"},
    {"hardwarelength", T_USHORT, offsetof(ARPObject, ar_hln), 0, "ARP hardware address length"},
    {"protocollength", T_USHORT, offsetof(ARPObject, ar_pln), 0, "ARP protocol address length"},
    {"hardwareformat", T_USHORT, offsetof(ARPObject, ar_hrd), 0, "ARP hardware type"},
    {"sourcehardware", T_OBJECT, offsetof(ARPObject, ar_sha), 0, "ARP source hardware address"},
    {"targethardware", T_OBJECT, offsetof(ARPObject, ar_tha), 0, "ARP target hardware address"},
    {"sourceprotocol", T_OBJECT, offsetof(ARPObject, ar_spa), 0, "ARP source protocol address"},
    {"targetprotocol", T_OBJECT, offsetof(ARPObject, ar_tpa), 0, "ARP target protocol address"},

    {"packet", T_OBJECT, offsetof(ARPObject, data), READONLY, "Raw packet data"},
    { NULL }
};


PyTypeObject ARP_Type =
{
    /* The ob_type field must be initialized in the module init function
    * to be portable to Windows without using C++. */
    PyObject_HEAD_INIT(NULL)
    0,                        /*ob_size*/
    "pycap.protocol.arp",               /*tp_name*/
    sizeof(ARPObject),        /*tp_basicsize*/
    0,                        /*tp_itemsize*/
    /* methods */
    (destructor)ARPObject_dealloc, /*tp_dealloc*/
    0,                /*tp_print*/
    0,                        /*tp_getattr*/
    0,                        /*tp_setattr*/
    0,                        /*tp_compare*/
    (reprfunc)ARPObject_str,  /*tp_repr*/
    0,                        /*tp_as_number*/
    0,                        /*tp_as_sequence*/
    0,                        /*tp_as_mapping*/
    0,                        /*tp_hash*/
    0,                        /*tp_call*/
    (reprfunc)ARPObject_str,  /*tp_str*/
    0,                        /*tp_getattro*/
    0,                        /*tp_setattro*/
    0,                        /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT,       /*tp_flags*/
    "ARP packet",             /*tp_doc*/
    0,                        /*tp_traverse*/
    0,                        /*tp_clear*/
    0,                        /*tp_richcompare*/
    0,                        /*tp_weaklistoffset*/
    0,                        /*tp_iter*/
    0,                        /*tp_iternext*/
    ARPObject_methods,        /*tp_methods*/
    ARPObject_members,        /*tp_members*/
    0,                        /*tp_getset*/
    0,                        /*tp_base*/
    0,                        /*tp_dict*/
    0,                        /*tp_descr_get*/
    0,                        /*tp_descr_set*/
    0,                        /*tp_dictoffset*/
    0,                        /*tp_init*/
    0,                        /*tp_alloc*/
    ARPObject_new,            /*tp_new*/
    0,                        /*tp_free*/
    0,                        /*tp_is_gc*/
};

int initARPType(PyObject *module_dict)
{
    if (PyType_Ready(&ARP_Type) < 0)
        return 1;

    PyDict_SetItemString(module_dict, "arp", (PyObject *) &ARP_Type);
    return 0;
}

Tags: pyselfreturnaddressprotocolnullarpyobject
1条回答
网友
1楼 · 发布于 2024-10-03 13:24:04

这些模块有.c元素来加速处理(即它们不是纯的python),因此需要根据平台进行不同的处理。在

在非windows系统上

您需要运行:

python setup.py build
python setup.py install

在非windows系统上。在

MS Windows系统

在windows系统上,您要么安装所有合适的工具,然后再像非windows系统一样执行相同的操作,要么找到并安装一个windows版本,以匹配python的版本。在

在Christoph Gohlke在他的Unofficial Windows Binaries for Python Extension Packages中提供了Pypi所指的正式版本之后,请注意python工具的Windows版本中最有用的一个页面,因此如果您在PyPi上找不到Windows版本,或者在项目主页上找不到,那么就在那里试试。

两者兼而有之

不管怎样,适当的二进制文件都会在.egg文件中,而您只需导入模块并使用函数。在

提示

在几乎任何python库上尝试的几个技巧: 在python终端中,(为这个冗长的示例道歉)

^{pr2}$

对发布的代码的快速解释

为了澄清问题中发布的代码-一旦您执行了上述步骤并导入了包,它将向名称空间添加一个新的类类型arp-这是通过PyDict_SetItemString(module_dict, "arp", (PyObject *) &ARP_Type);行来完成的,这些成员和方法在{}和{}中定义,这些成员和方法有望记录在模块文档中。在

相关问题 更多 >