Websocket+protobuf怎么与服务器通信

Websocket+protobuf怎么与服务器通信

Websocket:WebSocket是⼀种⽹络传输协议,可在单个TCP连接上进⾏双全⼯通信,位于OSI模型的
应⽤层
在这里插入图片描述

实现⼀个简单的客⼾端和服务端

安装websockets

 pip3 install websockets

客户端代码

import asyncio
import websockets

async def hello():
	uri = "ws://localhost:8765"
	async with websockets.connect(uri) as websocket:
		while True:
			name = input("What's your name?: ")
			await websocket.send(name)
			print(f"> {name}")
			greeting = await websocket.recv()
			print(f"< {greeting}")
if __name__ == "__main__":
	asyncio.get_event_loop().run_until_complete(hello())

服务端代码

import asyncio
import websockets

async def hello(websocket):
	while True:
		name = await websocket.recv()
		print(f"< {name}")

		greeting = f"Hello {name}!"

		await websocket.send(greeting)
		print(f"> {greeting}")
if __name__ == "__main__":
	start_server = websockets.serve(hello, "localhost", 8765)
	asyncio.get_event_loop().run_until_complete(start_server)
	asyncio.get_event_loop().run_forever()

websockets 是⼀个⽤于在 Python 中构建WebSocket服务器和客⼾端的库,专注于正确性、简单性、健壮性和性能。它建⽴在 Python 的标准异步 I/O 框架之上 asyncio ,提供了⼀个优雅的基于协程的 API。

Protobuf

protobuf全称Google Protocol Buffers,是google开发的的⼀套⽤于数据存储,⽹络通信时⽤于协议编解码的⼯具库。protobuf是⼀种灵活⾼效的独⽴于语⾔平台的结构化数据表⽰⽅法

probuf⽂档
在这里插入图片描述
protobuf与语言无关,protobuf转化成Python protoc --python_out=. ./user.proto

定义一个proto文件

syntax = "proto3";

message User {
string name = 1;
}

执行protoc --python_out=. ./user.proto,转化成Python结构体后将Python结构体转化成字节流,进行通信

user = user_pb2.User()
user.name = "张三"
data = user.SerializeToString()

粘包问题

拿我们的举例的PB⽂件来说:

syntax = "proto3";
message User {
string name = 1;
}

Q: 怎么知道你传过来的name⻓度是多少?
在这里插入图片描述
A:加上包头,根据包头的信息读取包的⻓度。
在这里插入图片描述
在Python中没有结构体的概念,所以⽤struct操作字节流

import struct
print("len(hello)=", len(bytes("hello", encoding="utf8")))
print("pack=", struct.pack('>I5s', 12341234, bytes("hello", encoding="utf8")))
print("unpack=", struct.unpack('>I5s', b'\x00\xbcO\xf2hello'))
  • I 表⽰接下来是⼀个四个字节的int 12341234
  • 5S表⽰接下来是五个Char
  • 表⽰⼤端,⽹络端

UDP/TCP/IP协议规定:把接收到的第⼀个字节当作⾼位字节看待,这就要求发送端发送的第⼀个字节是⾼位字节;⽽在发送端发送数据时,发送的第⼀个字节是该数值在内存中的起始地址处对应的那个字节,也就是说,该数值在内存中的起始地址处对应的那个节就是要发送的第⼀个⾼位字节所以:⽹络字节序就是⼤端字节序, 有些系统的本机字节序是⼩端字节序, 有些则是⼤端字节序, 为了保证传送顺序的⼀致性, 所以⽹际协议使⽤⼤端字节序来传送数据。
在这里插入图片描述

# client
import asyncio
import websockets
import user_pb2
import struct
async def hello():
	uri = "ws://localhost:8765"
	async with websockets.connect(uri) as websocket:
	user = user_pb2.User()
	user.name = "张三"
	data = user.SerializeToString()

	l = len(data)
	format = ">I%us" % l
	print("format=", format)
	buf = struct.pack(format, l, data)
	
	await websocket.send(buf)
	print(f"> {user.name}")
	
	ret = await websocket.recv()
	print(f"< {ret}")

if __name__ == "__main__":
	asyncio.get_event_loop().run_until_complete(hello())
# server
import asyncio
import websockets
import struct
import user_pb2


async def hello(websocket, path):
	buf = await websocket.recv()
	
	l = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]
	print('l=', l)
	format = ">%us" % l
	data = struct.unpack(format, buf[4:])
	print(data)
	user = user_pb2.User()
	user.ParseFromString(buf[4:])
	print("服务器收到名字, name=", user.name)
	
	greeting = f"I received!"
	await websocket.send(greeting)
	print(f"> {greeting}")


if __name__ == "__main__":
	start_server = websockets.serve(hello, "localhost", 8765)
	
	asyncio.get_event_loop().run_until_complete(start_server)
	asyncio.get_event_loop().run_forever()

以上就可以实现protobuf+websocket的通信了

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值