美文网首页
05.Python与C桥接编程-数据类型

05.Python与C桥接编程-数据类型

作者: 杨强AT南京 | 来源:发表于2018-11-03 01:41 被阅读35次

  这个主题专门针对Python的数据类型与C类型做一个对应。很多系统层面的C的开发基本上在Python中可以得到对应的移植应用。
  比如:在网络通信中,解析IP,UDP等协议包的时候,会用到以位为单位的内存操作。

本主题的内容:

  1. 把C中以为单位的内存中数据转换为Python中对应数据;
  2. 读取网络的IP数据包,并使用Python解析数据包中每个对应数据。

准备

  下面是IP协议数据包格式:

IP数据包格式说明

一. ctypes类型、C类型与Python类型

1. 类型对应表

ctypes type C type Python type
c_bool _Bool bool (1)
c_char char 1-character bytes object
c_wchar wchar_t 1-character string
c_byte char int
c_ubyte unsigned char int
c_short short int
c_ushort unsigned short int
c_int int int
c_uint unsigned int int
c_long long int
c_ulong unsigned long int
c_longlong __int64 or long long int
c_ulonglong unsigned __int64 or unsigned long long int
c_size_t size_t int
c_ssize_t ssize_t or Py_ssize_t int
c_float float float
c_double double float
c_longdouble long double float
c_char_p char * (NUL terminated) bytes object or None
c_wchar_p wchar_t * (NUL terminated) string or None
c_void_p void * int or None

注意:
  1. 上面类型还有别名,比如c_byte的别名就是class ctypes.c_uint8,别名体现了位数。
  2. 上面所有类型都继承class ctypes._SimpleCData,该类只有唯一的属性value

2. ctype类型使用例子

  代码1:整数

  import ctypes
  v = ctypes.c_int ( 2 )
  print ( v )
  print ( v.value )

  结果1:

c_int(2)
2

  代码2:字符串

  s = ctypes.c_wchar_p  ("这是一个字符串" )
  print ( s )
  print ( s.value )

  结果2:

c_wchar_p(4509017776)
这是一个字符串

  ctypes类型是Python类,可以转换为Python内置类型,该类的主要作用就是就是可以控制Python数据的位数。可以构造2个字节的整数等,这样对数据进行更加精确的操作。

3. 从字节序列中拷贝

  每个对应的类型还提供静态方法来产生对应的ctypes数据类型,这些静态方法来自所有ctypes类型的根类_CData类,该类不是public的,但其方法可以通过继承的方式在ctypes的每个类型中直接使用:

函数 函数说明
from_buffer(source[, offset]) 共享字节序列,产生对应的数据
from_buffer_copy(source[, offset]) 从字节序列中拷贝,产生对应的数据
from_address(address) 从一个地址产生对应的数据
from_param(obj) 把一个python的数据obj,适配成C的参数
in_dll(library, name) 加载在共享库中定义的变量

  代码:(从动态库与地址加载例子暂时不列出来)

#从其他字节序列中拷贝
v2=ctypes.c_int.from_buffer(v,0)
print(v2,v2.value)
a=20
v3=ctypes.c_int.from_param(a)
print(v3)

  结果:

c_int(2) 2
<cparam 'i' (20)>

提示:
  1. 有了ctypes,python的数据可以采用更优的内存存储,比如在Python没有1字节或者2字节整数,使用ctypes就可以产生2字节整数(类型为c_short或者c_int16),这是Python类型没有办法实现的事情。
  2. 更加有用的是,我们可以利用from_buffer函数直接使用2字节转换成整数(在后面的综合例子中可以说明)。
  3. ctypes类型可以作为字节序列使用。


二、在Python中使用结构体

  Python中没有结构体,通过结构体,可以批量存储不同字节的数据,尤其在把字节序列批量转换成多个数据的时候特别有用,比如把IP数据包按照格式读取特别方便。同时Structure的父类也是_CData,也可以调用from_buffer等函数。

1. 使用python内置数据构造结构体

  构造Python结构体,遵循如下几个步骤:
    |-继承ctypes.Structure类;
    |-定义结构体每个字段的名字与类型
    |-构造结构体对象
    |-访问结构体中数据
  其中字段的定义在fields中定义。fields是个list类型,每个元素由元组构成('字段名',类型,位数)
  代码:

import ctypes
#结构体
class Point(ctypes.Structure):
    _fields_=[ ("x", ctypes.c_int),
               ("y", ctypes.c_byte, 4)]

p=Point(200,5)
print(p)
print(p.x,p.y)

  结果:

  <__main__.Point object at 0x10d6a72f0>
  200   5

2. 使用字节序列构造结构体

  使用字节序列构造结构体,需要把字节序列拷贝到结构体,或者共享字节序列空间,可以使用两种方式:
    |-方式一:覆盖__new__,定制内存存储方式
    |-方式二:使用from_buffer函数直接返回。
  实际上上述两种方式都要使用from_buffer构造存储空间。
  方式一实现代码:

import ctypes
#结构体
class Point(ctypes.Structure):
    _fields_=[("x",ctypes.c_byte,4),("y",ctypes.c_byte,4)]
    def __new__(self, buf):
        return self.from_buffer(buf,0)

a=ctypes.c_byte(20)
p2=Point(a)
print(p2.x,p2.y)

#p3=Point(2,2)  #这种方式就不能再使用,参数个数无法匹配

  方式一结果:

4 1

  方式二实现代码:

import ctypes
#结构体
class Point(ctypes.Structure):
    _fields_=[("x",ctypes.c_byte,4),("y",ctypes.c_byte,4)]
    
a=ctypes.c_byte(20)
p2=Point.from_buffer(a,0)
print(p2)
print(p2.x,p2.y)

  方式二结果:

  <__main__.Point object at 0x107c171e0>
  4 1

  y=1在高位第5个位,等于2^4x=4在低位,大家可以再回顾下二进制运算的游戏规则。

  方式一还可以在init构造器中对字段数据进行处理:

import ctypes
#结构体
class Point(ctypes.Structure):
    _fields_=[("x",ctypes.c_byte,4),("y",ctypes.c_byte,4)]
    def __new__(self, buf):
        return self.from_buffer(buf,0)
    #参数与__new__保持一致
    def __init__(self,buf):
        self.x=6

a=ctypes.c_byte(20)
p2=Point(a)
print(p2.x,p2.y)

  运行结果:

6 1

3. 使用结构体解析IP数据包

  注意:下面代码在Mac OS与Linux系统下运行,需要root用户。

#!/usr/bin/python
#coding=utf-8

import socket
import  struct
from ctypes import *

class IP(Structure):
    _fields_ = [
        ("ihl",             c_ubyte, 4),
        ("version",         c_ubyte, 4),
        ("tos",             c_ubyte),
        ("len",             c_ushort),
        ("id",              c_ushort),
        ("offset",          c_ushort),
        ("ttl",             c_ubyte),
        ("protocol_num",    c_ubyte),
        ("sum",             c_ushort),
        ("src",             c_uint),
        ("dst",             c_uint),
    ]
    def __new__(self, socket_buffer=None):
        return self.from_buffer_copy(socket_buffer)
    def __init__(self, socket_buffer=None):
        self.src_address = socket.inet_ntoa(struct.pack("<I", self.src))
        self.dst_address = socket.inet_ntoa(struct.pack("<I", self.dst))
        self.ver=self.version
sk=socket.socket(socket.AF_INET,socket.SOCK_RAW,0)
while True:
    buf=sk.recv(2048,0)
    ip_header = IP(buf[:20]) #可以使用from_buffer
    print(ip_header.src_address)
    print(ip_header.dst_address)
    print(ip_header.ver)

  说明:
  (1)其中使用struct在Python内置类型与字节序列的转换是另外一个话题,在单独的篇幅说明。
  (2)关于C动态库,函数指针,也使用单独的篇幅来说明。


资源

本主题代码列表:
  |-ctypes01_type.py
  |-ctypes02_struct.py
  |-ctypes03_struct.py
  |-ctypes04_struct_new.py
  |-ctypes05_struct_init.py
下载地址:
https://github.com/QiangAI/PythonSkill/tree/master/AdvPython/04ctypes

相关文章

  • 05.Python与C桥接编程-数据类型

      这个主题专门针对Python的数据类型与C类型做一个对应。很多系统层面的C的开发基本上在Python中可以得到...

  • 桥接:__bridge

    1>在ARC中,使用到和c语言对应的数据类型,应该使用__bridge桥接 2>在MRC中,不需要桥接 3>在OC...

  • 直接桥接与ARC桥接转换

    苹果公司为基于C的框架和基于OC的框架中的许多数据类型提供了互用性,这种功能称为直接桥接。ARC桥接转换:__br...

  • 在Swift工程里面使用OC文件(包括Cocopods导入的第三

    混合编程(Swift和Object-C共同编程)----这是一个过渡时期,你懂得!!! 生成桥接文件 使用自动生成...

  • 直接桥接数据类型和ARC桥接转换

    直接桥接数据类型: 苹果公司为基于C语言的CoreFundation和基于OC的Foundation框架中的很多数...

  • [iOS] Swift与Objective-C混编

    一. 创建Objective-C混编桥接文件 当Swift与OC混编时,需要创建桥接文件,才能在OC中使用Swif...

  • __bridge的用法

    __bridge作为OC与C语言之间的桥接符号使用, 简单的用法:

  • 现实中的模式应用

    桥接模式 针对接口编程,就是桥接模式 策略模式 策略模式也可看作是针对接口编程 状态模式 状态模式通过 Conte...

  • C++ 中的变量

    C++ 中的变量内存数据类型 C++ 数据类型 使用编程语言进行编程时,需要用到各种变量来存储各种信息。变量保留的...

  • C++中类和结构体区别

    C的struct与C++的class的区别:struct只是作为一种复杂数据类型定义,不能用于面向对象编程。 C+...

网友评论

      本文标题:05.Python与C桥接编程-数据类型

      本文链接:https://www.haomeiwen.com/subject/cidhxqtx.html