带有 C 库的 Python

标签 python c

我一直在寻找 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 *类型,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;
}

最佳答案

这些模块有 .c 元素来加速处理,(即它们不是 python),因此需要根据平台区别对待。

在非windows系统上

你需要运行:

python setup.py build
python setup.py install

在非 Windows 系统上。

MS-Windows 系统

在 Windows 系统上,您将必须安装所有适当的工具,然后执行与非 Windows 系统相同的操作,或者找到并安装一个 Windows 版本以匹配您的 Python 版本。

请注意在 Pypi 指向的官方构建之后,Python 工具的 Windows 构建最有用的页面之一。由 Christoph Gohlke 在他的 Unofficial Windows Binaries for Python Extension Packages 中提供所以如果你没有找到基于 PyPi 的 Windows ,或项目主页,然后在那里尝试。

两者

无论哪种方式,适当的二进制文件都将在 .egg 文件中,您只需导入模块并使用函数即可。

提示

尝试几乎所有 python 库的几个技巧: 在 python 终端中,(为拉伸(stretch)示例道歉):

import parrot          # Or whatever your library is called
dir(parrot)            # This will give you a list of methods and members of parrot
dir(parrot.Norwegian)  # Assuming that parrot has a member by that name
help(parrot)           # Will give top level help followed by help on the members
help(parrot.Norwegian) # Should tell you that it has a member Blue that doesn't do a lot

发布代码的快速解释

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

关于带有 C 库的 Python,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21227992/

相关文章:

python - 如何在Selenium Webdriver中模拟HTML5拖放?

C子进程没有收到SIGINT信号

objective-c - malloc 后 char* 大小与预期不同

python - Pandas 浅复制 DataFrame 的两列

python - 如何在 Python 中就地解压列表或元组?

python - Numpy 索引切片而不丢失维度信息

Python - 快速修复属性错误: sessionID

c - GLIBC:调试内存泄漏:如何解释 mtrace() 的输出

c - 如何使用两个或多个迭代器在 for 循环内递增

c - yacc:在 yyparse() 方法中使用文件指针