欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C语言与Python平台通过socket建立结构型方式数据传输通信(使用struct.pack())

程序员文章站 2022-04-24 22:33:35
...

解决的问题:1)Python与C跨平台通信(结构型数据传输方式)
2)接收端无故多出0x00字节

TCP/IP协议下,主要有两种通信方式:
1、字符流:字符串形式,没有平台不一致问题,但传输的数据不定长,复合数据类型(如struct)的解析不方便;
2、结构型:按数据类型传输,保证数据长度固定/可控,方便对接受到数据的解析;但前提是要考虑平台不一致问题,如字节序、对齐位宽、数据类型等。

本文采用Python平台编写上位机,C编写下位机,并且按照结构型传输数据,为了将数据转化成在内存中的二进制串结构体数据(C中所用的结构体数据)以供下位机接收,可以用到struct.pack()struct.unpack()
使用方式示例:

##在2i1d1B1B1B1B前加上!,防止int与double数据交界处为了对齐而自动补上的一个四字节的0,同时会改变大小端

import struct
import string
def main():
    data_int1 = 256
    data_int2 = 122
    data_float = 120.04
    data_float2 = 30.23
    data_head1 = 0xff
    data_head2 = 0xff
    data_head3 = 0xff
    data_head4 = 0xff
    '''
    如果按网络传输接收到字符串,可在2i1d1B1B1B1B前加上!,改为!2i1d1B1B1B1B,会改变大小端
    上位机通过socket.recv接收到了一个c语言编写的下位机的结构体数据,存在字符串dataTobytes中
    a, b, c , d, e, f, g= struct.unpack('!2i1d1B1B1B1B', dataTobytes),
    2i表示对应于c语言2个4字节int类型数据
    1d表示对应于c语言1个8字节double类型数据
    1B表示对应于c语言一个字节无符号char
    '''
    dataTobytes = struct.pack('2i2d1B1B1B1B', data_int1, data_int2, data_float,data_float2, data_head1,data_head2, data_head3, data_head4  )
    print(type(dataTobytes[0:4]), len(dataTobytes))
    # print(dataTobytes[0])
    # print(dataTobytes[1])
    # print(dataTobytes[2])
    # print(dataTobytes[3])
    # print(dataTobytes[4])
    '''
    dataTobytes为字符串,对应于data_int1, data_int2, data_float, data_head1,data_head2, data_head3, data_head4在内存中的二进制串
    如,前四个字节传送的是data_int1,则前面四个字符为0x00,0x01,0x00,0x00
    '''
    #dataTobytes = struct.pack('2i1d', data_int1, data_int2, data_float )
    a, b, c , d, e, f, g,h= struct.unpack('2i2d1B1B1B1B', dataTobytes)
    # a, b, c = struct.unpack('2i1d', dataTobytes)
    # print(a)
    # print(b)
    # print(c)
    # print(d)
    # print(e)
    # print(f)
    # print(g)

    # 打印浮点数120.04和30.23的二进制串
    for i in range(8,24):
        print(dataTobytes[i])
if __name__ == "__main__":
    main()

之后用send向下位机发送dataTobytes即可:

server.send(dataTobytes)

Note: 有时候为了对齐,不同类型数据交接处系统会补充0(也就是无故多出0x00字节),此时要在2i2d1B1B1B1B前加上”!”(会修改为大端模式对齐)。
1.网络数据(socket)传输总结见:
https://blog.csdn.net/wangzuojoe/article/details/5163102
2.struct.pack()和struct.unpack()用法详解见:
https://blog.csdn.net/weiwangchao_/article/details/80395941?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160099634819195188313115%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=160099634819195188313115&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v3~pc_rank_v2-2-80395941.first_rank_ecpm_v3_pc_rank_v2&utm_term=struct.pack&spm=1018.2118.3001.4187

3.大端小端(高低位字节)详解见:
https://blog.csdn.net/aigoV/article/details/78706609?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160099674719725271749622%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=160099674719725271749622&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v3~pc_rank_v2-1-78706609.first_rank_ecpm_v3_pc_rank_v2&utm_term=%E9%AB%98%E4%BD%8D%E4%BD%8E%E4%BD%8D&spm=1018.2118.3001.4187