首页 > 编程语言 >python服务器/客户模型代码 之三

python服务器/客户模型代码 之三

时间:2024-09-14 23:19:56浏览次数:8  
标签:struct python 之三 缓冲区 格式 字符串 服务器 data socket

python服务器/客户模型代码 之三

python的struct

多个struct函数(Struct 的方法)采用缓冲区参数。这个对象实现缓冲区协议,并提供可读或可读写缓冲区。用于此目的的最常见python类型是 bytes 和 bytearray,但许多其他可以视为字节数组的类型实现缓冲区协议,以便可以读取/填充它们,而无需从 bytes 对象进行额外的复制。

格式字符串描述了打包和解包数据时的数据布局。它们由格式字符组成,格式字符指定要打包/解包的数据类型。此外,特殊字符控制字节顺序、大小和对齐方式。每个格式字符串都包含一个可选的前缀字符(描述数据的整体属性)和一个或多个格式字符(描述实际数据值和填充)。

格式字符串

格式字符串的第一个字符

格式字符串的第一个字符可用于指示打包数据的字节顺序、大小和对齐方式,如下表所示

字符字节序大小对齐
@nativenativenative
=native标准
<小端顺序标准
>大端顺序标准
!网路序标准

native依赖主机。

格式字符

考虑到它们的类型,C 和 Python 值之间的转换应该是显而易见的。

当格式字符串第一字符是 ‘<’、‘>’、‘!’ 或“=”,“标准大小”是指使用标准大小时打包值的大小(以字节为单位)。

当格式字符串第一字符是 ‘@’,打包值的大小取决于平台。

格式字符C 类型Python 类型标准大小
xpad byteno value
ccharbytes of length 11
bsigned charinteger1
Bunsigned charinteger1
?_Boolbool1
hshortinteger2
Hunsigned shortinteger2
iintinteger4
Iunsigned intinteger4
llonginteger4
Lunsigned longinteger4
qlong longinteger8
Qunsigned long longinteger8
nssize_tinteger
Nsize_tinteger
e(6)float2
ffloatfloat4
ddoublefloat8
schar[]bytes
pchar[]bytes
Pvoid*integer

pack

struct.pack(format, v1, v2, …)
返回一个bytes对象,该对象包含v1、v2、…值,这些值根据格式字符串格式组合在一起。参数必须与格式所需的值完全匹配。

struct.pack_into(format, buffer, offset, v1, v2, …)
根据格式字符串格式,该函数将v1、v2、…值组合在一起,并将打包字节写入从位置 offset 开始的可写缓冲区 buffer。

unpack

struct.unpack(format, buffer)
根据格式字符串 format 从缓冲区 buffer 中解包。结果是一个元组,即使它只包含一项。缓冲区的大小(以字节为单位)必须与格式所需的大小相匹配。格式所需的大小可以使用calcsize() 来计算。

struct.unpack_from(format, /, buffer, offset=0)
根据格式字符串格式,从偏移位置开始从缓冲区解包。结果是一个元组,即使它只包含一项。缓冲区的大小(以字节为单位)从位置偏移量开始,必须至少为格式所需的大小,格式所需的大小可以使用calcsize() 来计算。

struct.iter_unpack(format, buffer)
根据格式字符串格式迭代地从缓冲区 buffer 中解包。该函数返回一个迭代器,它将从缓冲区读取相同大小的块,直到其所有内容都被消耗。缓冲区的大小(以字节为单位)必须是格式所需大小的倍数。

每次迭代都会生成一个由格式字符串指定的元组。

struct 数据传输

struct.Struct(format)

返回一个新的 Struct 对象,该对象根据格式字符串格式写入和读取二进制数据。创建一次 Struct 对象,并调用其方法比调用具有相同格式的模块级函数更有效,因为该对象仅编译一次格式字符串。

pack

pack(v1, v2, …)
与 pack() 函数相同,但使用编译后的格式字符串。len(result)等于该Struct 对象的size。

pack_into(buffer, offset, v1, v2, …)
与 pack_into() 函数相同,使用编译后的格式字符串。

unpack

unpack(buffer)
与 unpack() 函数相同,使用编译后的格式字符串。缓冲区的大小(以字节为单位)必须等于该Struct 对象的size。

unpack_from(buffer, offset=0)
与 unpack_from() 函数相同,使用编译后的格式字符串。缓冲区的大小(以字节为单位)从位置 offset 开始,必须至少为 size。

iter_unpack(buffer)
与 iter_unpack() 函数相同,使用编译后的格式字符串。缓冲区的大小(以字节为单位)必须是 该Struct 对象的size 的倍数。

server代码

import socket
import sys
from struct_data import *

def serve_connect(connection, client_address):
    try:
        print ('connection from', client_address)
        data = struct_data(connection, PKT_PACK_HEAD_FMT, PKT_PACK_BODY_FMT, PKT_PACK_ID, FIELD_NAMES)
        s_data = data.receive_packet()
        s_data["name"]=s_data["name"].decode("utf-8").strip('\x00')
        print('received: {0}'.format(s_data))
        
        resp = struct_data(connection, RESP_PKT_PACK_HEAD_FMT, RESP_PKT_PACK_BODY_FMT, RESP_PKT_PACK_ID, RESP_FIELD_NAMES)
        
        data_s = {"employee_id":s_data["employee_id"], "status":1}
        memb_data = list(data_s.values())
        bdata = resp.make_packet(memb_data);
        connection.sendall(bdata)
    finally:
        # Clean up the connection
        connection.close()    

def tcp_server():
    # Create a TCP/IP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # Bind the socket to the port
    server_address = ('localhost', 10000)
    print('starting up on %s port %s' % server_address)
    sock.bind(server_address)

    # Listen for incoming connections
    sock.listen(1)

    while True:
        # Wait for a connection
        print('waiting for a connection')
        connection, client_address = sock.accept()
        serve_connect(connection, client_address)

if __name__ == "__main__":
    tcp_server()

client代码

import socket
import sys

from struct_data import *

def tcp_client():
    # Create a TCP/IP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # Connect the socket to the port where the server is listening
    server_address = ('localhost', 10000)
    print('connecting to %s port %s' % server_address)
    sock.connect(server_address)

    try:    
        data = struct_data(sock, PKT_PACK_HEAD_FMT, PKT_PACK_BODY_FMT, PKT_PACK_ID, FIELD_NAMES)

        data_s = {"employee_id":10020, "name":"John", "age":30, "height":175}
        memb_data = list(data_s.values())
        bdata = data.make_packet(memb_data);
        sock.sendall(bdata)
        
        resp = struct_data(sock, RESP_PKT_PACK_HEAD_FMT, RESP_PKT_PACK_BODY_FMT, RESP_PKT_PACK_ID, RESP_FIELD_NAMES)
        s_data = resp.receive_packet()
        print('received: {0}'.format(s_data))
        
    finally:
        print('closing socket')
        sock.close()    

if __name__ == "__main__":
    tcp_client()

辅助代码

辅助代码使用python的库,在python的值和C结构之间, 转换数据。在python中,C结构被表达成python的bytes类型。
这种方法可用于

  • 与外部源(比如网络)交换数据
  • 在python应用与C语言之间交换数据

struct_data.py包含下列的代码内容

import struct

from struct_data_const import *

class  struct_data:
    def __init__(self, conn, fmt_head_str, fmt_body_str, pack_id, field_names):
        self.fmt_head_str = fmt_head_str;
        self.fmt_body_str = fmt_body_str;
        self.conn = conn
        self.pack_id = pack_id
        self.field_names = field_names
        
    def make_packet(self, data):
        body_sz = struct.calcsize(self.fmt_body_str)
        b_head_data = struct.pack(self.fmt_head_str, self.pack_id, body_sz);
        
        fmt = [i for i in self.fmt_body_str]

        ndx = 0
        b_body_data=bytes(bytearray())
        
        cnt = 0;
        for x in fmt[1:]:
            if x>='0' and x <='9':
                cnt = cnt * 10 + int(x)
                continue
            elif cnt == 0:
                cnt = 1
            fmt1 = "{0}{1}{2}".format(fmt[0], cnt, x)
            cnt = 0

            if x == 's':
                b_body_data += struct.pack(fmt1, data[ndx].encode("utf-8"))
            else:
                b_body_data += struct.pack(fmt1, data[ndx])
            ndx = ndx + 1

        bdata = b_head_data + b_body_data
        return bdata

    def unpack_packet(self, fmt_str, data):
        dict_data = struct.unpack(fmt_str, data)
        return dict_data

    def receive_packet(self):
        sz = struct.calcsize(self.fmt_head_str)
        data = self.conn.recv(sz)
        
        l1 = self.unpack_packet(self.fmt_head_str, data);
        d1 = dict(zip(FIELD_HEAD_NAMES, l1))
      
        body_data = self.conn.recv(d1["len"])
        l2 = self.unpack_packet(self.fmt_body_str, body_data);
        b1 = dict(zip(self.field_names, l2))
        return b1

struct_data_const.py包含下列的代码内容

FIELD_NAMES = ["employee_id", "name", "age", "height"]
PKT_PACK_FMT = "<HH10sBH"
PKT_PACK_BODY_FMT = "<H10sBH"

FIELD_HEAD_NAMES = ["id", "len"]
PKT_PACK_HEAD_FMT = "<HH"

RESP_FIELD_HEAD_NAMES = ["resp_id", "len"]
RESP_PKT_PACK_HEAD_FMT = "<HH"

RESP_FIELD_NAMES = ["employee_id", "status"]
RESP_PKT_PACK_BODY_FMT = "<HB"

PKT_PACK_ID = 0xDAFE
RESP_PKT_PACK_ID = 0xDBFE

标签:struct,python,之三,缓冲区,格式,字符串,服务器,data,socket
From: https://blog.csdn.net/IT_Beijing_BIT/article/details/142236667

相关文章

  • D01【python接口自动化学习】-python基础
    day01变量学习日期:0908学习目标:变量的用法(如何让计算机临时存储数据?)学习笔记:添加变量使用input赋值为变量赋值#变量可重复赋值x=123print(x)x=456print(456)#连续赋值y=xprint(y)z=y=xprint(y)为变量赋值的不同写法#同时为不同变量赋不同的值,变量......
  • Python实现牛顿法 目录
    博客:Python实现牛顿法目录引言什么是牛顿法?牛顿法的历史与背景牛顿法的应用场景牛顿法的原理牛顿法的基本思想导数与泰勒展开的概念公式推导收敛性分析Python实现牛顿法面向对象的设计思路代码实现示例与解释牛顿法应用实例:求解非线性方程场景描述算法实现结果......
  • Python实现梯度下降法
    博客:Python实现梯度下降法目录引言什么是梯度下降法?梯度下降法的应用场景梯度下降法的基本思想梯度下降法的原理梯度的定义学习率的选择损失函数与优化问题梯度下降法的收敛条件Python实现梯度下降法面向对象的设计思路代码实现示例与解释梯度下降法应用实例:线......
  • D03【python接口自动化学习】-python基础
    day03字符串(下)学习日期:0910学习目标:字符串(下):python是如何处理单词的?学习笔记:#定义字符串print("hello,world")#hello,world#双引号定义字符串,字符串中有双引号,可用\转义print("hello\"world")#hello"world#字符串中有多个双引号,可用单引号定义字符串pr......
  • D04【python接口自动化学习】-python基础
    day04数字类型学习日期:0911学习目标:day04数字类型:存储数字应该用哪种数据类型?学习笔记:数字类型及组成数字类型的常见运算数字类型的强制转换#浮点数转换为整数print(int(123.45))#打印变量的类型x=1234print(type(x))#<class'int'>#字符串转......
  • D06【python接口自动化学习】-python基础
    day06注释学习日期:20240913学习目标:注释:如何写程序的说明书?学习笔记:1.1 如何编写注释注释的位置注释写在代码上面,是最常用的形式注释写在代码前面,常用于代码调试注释的内容怎么写注释要解释代码是做什么,以下建议注释2,不采用注释1python之禅总结注释......
  • D02【python接口自动化学习】-python基础
    day02字符串(上)学习日期:0909学习目标:字符串(上):python是如何处理单词的?学习笔记:字符串的常用方法#字符串常用方法#打印字符串的个数print('xyxyxyz'.count('x'))#输出3print('xyxyxyz'.count('xy'))#输出3print('xyxyxyz'.count('a'))#输......
  • python实现插入排序算法
    插入排序是指,在已经排序过的列表,将需要添加的数据从开头依次进行比较,找到保存的位置,并将数据进行插入排序的方法。比如列表6,15,4,2,8,5,11,9,7,13第一步6和15比较,15大,不用比较。第二步4和前面两个数比较,就是6和15,4最小,将4插入到最前面。编程语言如何实现这个过程,将4和前......
  • Python基础入门1
    1.注释和标识符print("helloworld")#单行注释以#开头'''多行注释三个引号开头,三个引号结尾,可以是单引号或者双引号''''''标识符:主要指作为:变量、函数、类模块以及其他对象的名称。1.有数字,下划线,字母组成,但是数字不能开头2.区分大小写3.不能使用关键字(报错了直......
  • python 自动化运维
    Python 是一种动态的高级编程语言,语法非常简洁,初学者很容易上手。Python 语言表达力非常强大,三两行代码即可完成其他编程语言可能要写几十上百行的功能,开发效率非常高。因此,它经常作为胶水式语言,在自动化运维等开发领域大显身手。语法简洁,易于学习表达力强大,开发效率高执行效率不......