Comments (8)
感谢您的回复
JS Client 是能收到消息,但是被截断了,以下是浏览器的输出:
实际 Server 端发送的消息是:
也非常感谢您的建议
- 没有加锁是我的疏忽,由于写的是 Demo,没有考虑太多了。
- Server 的 HandleDisconnected 我原以为是 Server 端终止的时候会调用的回调,感谢您的建议。
- 我的确是想着同一个端口处理 ws 和 rpc,也感谢您的建议。
from arpc.
是否有遇到您疑惑的点相关的bug,如果遇到,请提供下能够复现的完整示例代码我这边排查下。
我先对于您疑惑的几个点做一下解释:
您好,请问一下,有关 websocket 的消息截断的问题,在 onMessage 函数下,通过 offset 去循环处理一段消息,这里使用 offset 的原因是什么?
我在使用的时候,发现 bodyLen 的长度计算不正确,例如我从服务器推送一条 Notify 的消息,在这里断点,得到的 event.data.byteLength 长度是 645,然而通过 bodyLen 计算出来的结果是 119,即使这是在 while 循环中,offset 会在下一次循环开始前偏移,但是消息已经在第一次循环里就发送给 handle 了
这是由于 server 端默认是 批次发送 的,默认提供的websocket扩展是基于gorilla/websocket.Conn进行封装实现了 net.Conn 的接口,websocket.Conn 只是作为 net.Conn 接口,当发生批次发送时,server会把多个 arpc Message 合并成一段 buffer 执行 websocket.Conn 封装的 Write:
https://github.com/lesismal/arpc/blob/master/client.go#L781
https://github.com/lesismal/arpc/blob/master/client.go#L845
所以,虽然 websocket 本身不需要处理所谓的 粘包
,但在默认提供的扩展中仍存在一个完整 websocket Message 可能包含多个 arpc Message 情况,所以这里需要循环处理、而不是把一个 websocket Message buffer 就当成一个 arpc Message 的 buffer
还有另一个问题是,第二次循环中,header 的内容并不存在,计算的 method 或者其他信息都是原来消息体的一部分信息,即使想要组装数据,似乎也没法完成。
上面已经讲到,一个 websocket Message 可能包含多个 arpc Message,并且本身封装的 Write 也是调用 WriteMessage,所以可以保证一个 websocket Message 中一个或者多个 arpc Message 的完整性,不需要担心 js client 解析时遇到半个 arpc Message 的问题,所以要么 offset 已经大于 websocket Message 长度结束循环,要么 headerArr 就正常拿到完整包头:
https://github.com/lesismal/arpc/blob/master/extension/jsclient/arpc.js#L182
from arpc.
上面我写的部分代码就是例子了……
可能比较麻烦,我重写了一个 Demo 打包发给您,在写的过程中我发现了另一个问题,就是如果使用这种订阅模式,另一个客户端如果不是 web 端,而是 server 端的话,会出现 timeout 的情况,在代码里我也一并打包给您了。
单纯运行 server 的程序,然后打开网页端就是我说的上述没有正确分段导致 websocket Message 截断的问题;
在运行 server 程序的前提下,在另一个终端运行 client 程序,就会出现新发现的 timeout 问题;
代码均在 main.go 中,要编译 client 程序,将 main() 里面的 server [部分代码注释,其余部分解开注释即可。
pinDemo.zip
from arpc.
上面我写的部分代码就是例子了……
可能比较麻烦,我重写了一个 Demo 打包发给您,在写的过程中我发现了另一个问题,就是如果使用这种订阅模式,另一个客户端如果不是 web 端,而是 server 端的话,会出现 timeout 的情况,在代码里我也一并打包给您了。
单纯运行 server 的程序,然后打开网页端就是我说的上述没有正确分段导致 websocket Message 截断的问题;
在运行 server 程序的前提下,在另一个终端运行 client 程序,就会出现新发现的 timeout 问题;代码均在 main.go 中,要编译 client 程序,将 main() 里面的 server [部分代码注释,其余部分解开注释即可。
pinDemo.zip
你例子中的server用的是websocket,你指的超时应该是说go client的超时吧?因为你的go client用的是tcp协议,tcp连到go的 websocket上,websocket msg解析都没通。
另外代码中还有一些问题,比如:
- BroadcastClients 没加锁
- 不应该为每个新连接上来的client单独设置HandleDisconnected:
context.Client.Handler.HandleDisconnected(func(clientWhichDisconnected *arpc.Client) {
//remove from BroadcastClients
idx := indexOfClient(clientWhichDisconnected,BroadcastClients)
if idx >= 0 {
if length := len(BroadcastClients); length != 1 {
BroadcastClients[idx] = BroadcastClients[length - 1]
BroadcastClients = BroadcastClients[:length - 1]
}else {
BroadcastClients = BroadcastClients[:0]
}
}
});
而是应该为 server 的Handler 统一设置:
server.Handler.HandleDisconnected(...)
from arpc.
如果想既服务 ws 又服务 tcp,可以开两个端口分别处理不同的协议,如:
arpc.DefaultHandler.Handle("/auth", func(context *arpc.Context) {...}
arpc.DefaultHandler.HandleDisconnected(...)
ln, _ := websocket.Listen("ws addr", nil)
http.HandleFunc("/ws", ln.(*websocket.Listener).Handler)
wsServer := arpc.NewServer()
go wsServer.Serve(ln)
tcpServer := arpc.NewServer()
tcpServer.Run("tcp addr")
当然你也可以自己实现一个 listener,封装一层,根据Accept后根据读到的前几个字节判断是否为http upgrade ws,是则转给 ws server 否则转给 tcp server,这样可以实现共用一个端口来服务两个不同的协议,但是会有性能损失和不必要的复杂度。
当然,你也可以使用 websocket 作为 go client 的协议,但不如直接用tcp性能好。
from arpc.
JS Client 是能收到消息,但是被截断了,以下是浏览器的输出:
确实是,看了下代码,计算 body length 时多写了个 & 0xFF,导致只计算了第一个字节,稍等我修复更新上去。
感谢反馈!
from arpc.
已修复: 0f639ef
请尝试最新版本的 js client
from arpc.
赞👍
from arpc.
Related Issues (20)
- issue with client HOT 14
- 同学,您这个项目引入了204个开源组件,存在3个漏洞,辛苦升级一下 HOT 3
- 例子里的micro下面的client.go的serviceManager.ClientBy获取不到服务 HOT 6
- Is there an elegant way to handle multiple client sessions? HOT 5
- 为什么需要设计这个maxload? HOT 3
- 处理Notify消息错误 HOT 4
- data race问题 HOT 5
- 您好请问用php语言写rpc的client端有例子吗? HOT 2
- Could you update readme slack link? HOT 10
- timeout不工作的问题 HOT 7
- 请问server和client端是如何管理tcp连接的?需要业务层自己做连接池对连接进行复用吗? HOT 3
- 怎么添加和获取message.values HOT 11
- 可以类似http那种增加header信息吗? HOT 5
- client 调用 server 附带的 values 会被原样再发送回来,是否可控不发送 HOT 7
- client经常性出现client reconnecting的错误 HOT 12
- 模块管理的问题 HOT 27
- arpc.js in /extension is out of sync with /examples HOT 3
- panic when stopping service when duplicate routes are registered HOT 3
- Gin -> ARPC integration HOT 7
- can routes be added dynamically? HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from arpc.