1
ChefIsAwesome 2023-12-21 11:03:28 +08:00
搞个 id 啊
|
2
Zhuzhuchenyan 2023-12-21 11:29:47 +08:00
第一,websockets 作为一个单纯的协议并不应该关心客户端和服务端双方是如何对具体信息交互的,对于你的需求,唯一的方法就是自己封装一个更上层的解决方案来维护消息自身逻辑的收发有序性。
第二,从你给的代码,在第一次发送之后,在收到服务器回应之前,第二次信息不会被发送,自然也就不存在你所说的问题,我猜你想描述的是以下这种情况 await ws.send("read A") await ws.send("read B") await ws.send("read C") # 此时如何保证 A ,B ,C 分别是 Data A ,B ,C A=await ws.recv() B=await ws.recv() C=await ws.recv() |
3
beyondstars 2023-12-21 11:51:19 +08:00
您好,ws 自身的确无法保证 recv 和 send 的顺序一致。
ws 是为了解决什么问题呢?它主要是为了解决: 1 ) framing (因为 tcp 连接是一个 stream, tcp 连接是 boundless 的); 2 )连接复用; 3 )双向通信(让 server 也可以主动给 web client 发消息)。这些都跟顺序没关系。 你需要自己再在 ws 之上实现一层。 |
4
009694 2023-12-21 11:58:28 +08:00 via iPhone
你服务端乱序返回关 ws 协议啥事? ws 接收时本身严格遵循发送顺序 当你应用层本身乱了 就得靠应用层自己排序
|
5
spicy777 2023-12-21 12:29:52 +08:00 via iPhone
搞个 id 吧
|
6
QiShine OP 我就是想问问有没有现成的 await recv(ID),如果没有,那么我想的是建一个 dict {ID: queue of server messages},这样合理吗?有没有更好的办法?
|
7
LinePro 2023-12-21 14:38:39 +08:00
你可以自己封装 websocket 协议上层的处理。建一个 dict 存放 id 到 asyncio.Future 的映射。调用处 await 这个 future 。websocket 收到后从 dict 中取出对应的 future 并 set_result 。调用处的 await 就可以得到你设置的 result 内容。
|
8
realJamespond 2023-12-21 16:25:28 +08:00
服务器收到是按顺序的,但你咋保证它返回也按顺序? 我先返回 B 再返回 A 不行?
|
9
leonshaw 2023-12-21 16:46:59 +08:00
read B 和 Data B 有因果关系吗?如果有的话,看你代码 A=await ws.recv() 在 await ws.send("read B") 之前,那么 A 不可能是 Data B
|
10
cloud107202 2023-12-21 17:45:53 +08:00
@QiShine 没有 await recv(ID) 这种. websocket 设计上就是两个方向互不影响的流数据传送。你这个需求也许更适合 http/grpc 做那种传统 req-resp 的 pattern
|
11
ZZ74 2023-12-21 18:17:33 +08:00
无论是否有 recv 你发送是按顺序的 sendA sendB....那写入底层包括网络就是按 AB 顺序写入的,就不会乱序。到客户端网卡的时候也许会乱序,因为网络复杂,但是给你应用程序还是 AB 这个顺序
|
12
Trim21 2023-12-21 18:28:25 +08:00 via Android
听起来感觉你想在 websocket 上重新实现 http…
|
13
xiangyuecn 2023-12-21 18:34:11 +08:00
简单借鉴 http 的 request response ,一个 response 对应一个 request ,有的请求 1ms 返回响应,有的请求 100 秒返回响应
请求中简单加一个标记(比如消息编号),服务器返回响应时,原样携带此标记,代表是哪个 request 的 response |
14
QiShine OP @cloud107202 是不是可以有
dataA = await recv('A') doSomethingWith(dataA) dataB = await recv('B') doAnotherWith(dataB) 无论 AB 的响应,谁先来,都可以正常运行?像 erlang 里那样通过模式匹配来过滤消息队列 如果是 data = await recv() if data.ID == A: doSomethingWith(dataA) elif data.ID == B: doAnotherWith(dataB) 这样的话,肯定可以工作,但是把 A 和 B 的逻辑搅合在一起了,感觉不舒服。 没啥真实的需求,只是在熟悉 async 和 await 时的一点疑问。 |
15
QiShine OP @Zhuzhuchenyan 对,就是你说的这种情况。而且如果有 await ws.send('subscribe D'),后续就会有多次响应,就更复杂了,感觉用 await async 表达异步方式的逻辑,还是不自然。
|
16
dode 2023-12-22 10:43:50 +08:00
服务器加接口,abc 一次性发过去,服务器按顺序处理
|
17
cloud107202 2023-12-22 11:45:05 +08:00
@QiShine 就是你说的后面那种写法,这是业务的固有复杂度,躲不开的。看的不顺眼就抽象个 dispatcher 的逻辑
// data-flow-in: while(true) { bytes = await io.recv() // 反序列化 data = decode(bytes) // 派发 xxxhandler.process(data); // 再里面可以 if else } |
18
LinePro 2023-12-22 15:11:54 +08:00
之前撸过一份用 websocket 实现 jsonrpc 双向通信的客户端代码,可以参考一下。这里的双向通信是指既支持本地调用远程服务端的 rpc 接口,服务端也可以调用本地客户端提供的 rpc 接口。感觉异步 IO 的关键是要灵活使用 asyncio 提供的异步设施。封装好底层通信之后,上层业务处调用 rpc 就和调用一个普通函数一样简单了。
https://gist.github.com/linepro6/f51ac8930882ce8200f8a0ae795c214e |