当前位置: 首页 > 后端技术 > Python

用Python写网络程序(一)

时间:2023-03-25 22:27:45 Python

前言游戏行业与互联网是互通的。随着Http2.0-future的版本,更多的行业有更多的非Http请求任务。协议开始掌握:http、websocket、基础Tcp、基础UdpRpc、webRtc、Tars、Kcp、ENet序列化数据结构Protobuf、Thrift、Json、xml网络编程能力逐渐成为测试人员up的必备能力。以游戏行业为例,可以有以下功能:1.接口测试2.压力测试3.mock-创建环境数据(需要附加ssh服务器,导入所有配置表,修改数据库)4.Mock-GM工具(需要附加Mock和Do一些类似数据库存储过程的功能)5.平衡性测试(新手引导职业升级速度、抽卡、Pve副本、Pvp胜率、活动完成度等)6.对战验证(帧同步,状态同步)前后端在开发语言中有很多小细节。7.日志文件同步不过这个学习比较难,一部分原因是不能结合automation(随时找一个网页和app)和http接口(有教学接口),还有动手场景。后面要练习,需要自己写服务器来练习。还有一部分是需要网络知识的,希望通过这个来填补和掌握这个知识缺口。网络编程ClienttoServer客户端作为send发送消息--->ServerServertoClient客户端作为recv接收<----messages<----ServerServerpushClient服务器主动推送消息给client,比如小红积分,比如一些携带触发的消息,比如怪物的升级,服务器会把升级消息推送给Client。这里面有很多细节。比如C和S之间的连接是通过消息队列的,服务器mq是按帧保存的,比如最多保存500帧,每500帧清空一次。比如中间有压缩,签名或者加密,顺序不能乱,比如内存对齐,填充。这里面发送的消息是一个对象,对象是有数据结构的。这是网络编程时首先要学习的东西。socket建立后,必须设置socket的数据类型,基础的必须设置,是ipv4还是ipv6,数据流(tcp)还是数据包(udp)。管道建??立成功后,启动合约,后面会详细介绍。发送流程Client-->(msg原始数据容器)缓冲区-->(二进制)网卡-->(二进制)网关或其他-->(二进制)服务器这里注意一定要区分数据在外观上的区别内存(机器可以用)和自己查看(用于故障排除,基本是十六进制),不能认为是msg的原始形式。比如C#toString("x2")转换为十六进制,但是可以发送的时候切换成十六进制,就不会正确了。为什么不能那样转换,需要了解不同字符的长度,有些字符在二进制转换过程中会被自动翻译去掉,比如“\x”。msg原始数据容器分为以下几种类型:这里的容器是内存中的msg,容器不是基本数据类型1.string字符串没什么好说的,Python不区分char和string,而且用的时候不是二进制的,传到网卡的时候还是会翻译成二进制的。2、字节输出以b开头,表示是字节,由多个字节组成,也是一个字节数组,字节也可以拼接成长字节。字符串到字节的转换是通过encode()进行的。例如“helloworld”.encode()-->b'helloworld'。这里所做的是通过编译器对字符串进行编码,编码时默认为utf-8。utf-8向后兼容ascii码。3.bytearray字节都是一样的,但是bytearray内存是可变的。如何区分可变内存和不可变内存,因为以上三种数据类型必须是迭代器,迭代器是可以遍历的。t1="helloworld"t1[0]="a"t2="helloworld".encode()t2[0]="a"#上面写的会报错,因为内存是不可变的bytearray可以用object[0]分配。t2=bytearray([1,2,3])t2[0]=4print(t2)#\x04是因为t2[0]被修改了,bytearray(b'\x04\x02\x03')是可变的并且不可变变量在网络编程中也很重要。形参可以使用不可变的,形参不推荐使用可变的。调用一个函数会产生一个额外的副本。网络处理以上三种基本数据类型,bytes和bytearray的原始形式是二进制的,在大多数情况下,只有bytes可以作为网络编程的容器。这里,客户端需要将原始数据打包下发给网关。这里有一个概念,就是服务端不会收到客户端发来的所有东西。所有客户端都需要知道服务器可以接收什么数据类型(即,将为服务器转换成什么二进制文件)。我们不要在这里定义一个套接字来回发送。您必须首先知道您发送的内容是正确的。下面选择了最常见的字节。题目是客户端需要发送字节数据,每次不超过1450字节(最大传输单元),发送结果打印到控制台。这里有一个重要的知识点,字节不是字节,而是字节数组,一个字节占一个字节,基本数据类型(部分引用数据类型)在缓冲区中占用不同的位数,所以可以理解为字节的长度即这个字节数组的长度。defsession_bytes(datas:bytes,mtu:int=1450):"""客户端需要发送bytes数据,网络字节序为每次1450字节的bigendian最大传输单元,超过则分块分为2段,byteorder表示宿主字节顺序,big是bigendian。出现.to_bytes(2,byteorder="big")是因为byte数组是二进制的,所以在ord()中被转为int遍历时的记忆。:return:"""msg=[b"",b""]iflen(datas)>=mtu:foriindatas[:mtu]:msg[0]+=i.to_bytes(2,byteorder="big")foriindatas[mtu:]:msg[1]+=i.to_bytes(2,byteorder="big")其他:foriindatas:msg[0]+=i.to_bytes(2,byteorder="big")returnmsgPython语法不解释,注意注释。msg是有序的,网络传输在应用层是有序的。网络层的重传和组合由网络层操作。Python在应用层layer使用No.字节顺序决定最高字节在字节数组的开头还是结尾。表示具体的内容是先从左边传入还是从右边传入,左边是开头。这个是bigendian,客户端本地显示不重要,默认情况下可以使用print(sys.byteorder)在机器上打印,上面的例子设置字节顺序big为bigendian,用于标记网络缓冲区-网卡层传输。e字节顺序只需要与目标端和服务器端一致即可。Tips:是为了测试传入mtu时将bytes数据类型数据缩短。非基本数据类型Json这里就不用多说了。Json分别处理内存和文件。内存处理json.loads()和json.dumps()defjson_to_bytes(json_data:dict)->bytes:"""Json转换字节数组:paramjson_data:{"cat":"maomao"}:return:bytes"""ifisinstance(json_data,(str,dict)):returnjson.dumps(json_data).encode("utf-8")上面的例子将Json转成bytes。importxmltodict#pipinstallxmltodictdefxml_to_bytes(xml_out_put:str)->bytes:"""xml转换字节数组:paramxml_out_put::return:"""xml_data=xmltodict.parse(xml_out_put)data_json=json.dumps(xml_data,ensure_ascii=false)data_dict=json.loads(data_json)ifisinstance(data_dict,(str,dict)):returnjson.dumps(data_dict).encode("utf-8")xml这个比较古老,但是好处是Bring水平区域和坐标的概念。网络编程复习上面的内容基本都有,练完不用查网就可以写了。1.strings、bytes和bytearray的习题,操作slice,同类型的拼接,不满意的类型转换,length。2.学习bigendian和遍历bytes时的转换。3、Json和内存的处理方式有两种,xml部分可以顺便看下。