Comments (9)
比如上面的代码, 我觉得在recv结束之后, BeforeRecv 被再次调用了吧.
这有什么问题吗?每次读取完整协议包之前都应该按照当前时间更新deadline,如果只设置一次,比如:
setdeadline(15s) for { read }这样15s后、不管有没有数据过来,读都会失败。
哦哦, 是我想错了, 打扰了
新年快乐!
from arpc.
没太懂你意思,是指 for 循环中每次 read 之前都去调用 BeforeRecv 吗?如果是这个意思,那这个不是bug,对 conn 的处理通常包括两个地方:
一是建立连接时:可以通过HandleConnected处理新连接,这里通常用于设置一些conn基础参数,比如tcp read/write buffer size,这个设置后就不需要再更新设置了
二是对于 keepalive 的需求、需要经常更新超时时间,BeforeRecv主要是用于处理这个需求,心跳超时比较好的实现是每个连接每次读取一个完整协议包之前设置超时时间,也就是这里的 for 循环内的逻辑。其他一些框架也有使用单独的goroutine定时遍历所有连接、根据最后一次读取时间判断是否超时,这样会多消耗一个协程,并且如果在线量很大遍历成本有点高,而且对于每个连接都是不精确的
from arpc.
这里再多说一下 keepalive:
4层tcp也有keepalive的选项可以设置,但是4层的keepalive无法满足7层的需要,比如僵尸连接连到服务器上,tcp keepalive一直是健康的、4层协议本身一直保持连接不断开,但是这个僵尸连接什么都不做、空耗服务器资源。
所以7层通常仍需要自己进行心跳的逻辑、从而及时踢掉僵尸连接。
from arpc.
谢谢回复.
- 我的意思是在这个地方:
Line 723 in c3f8d6d
for循环里调用Recv(), 每个协议包读完之后,会重新进入循环, 再次调用Recv()里的beforeRecv, 之后才会被阻塞, 这样beforeRecv貌似会被调用两次? - 我也不太理解为什么keepAlive要在BeforeRecv里做而不在handler里做😂, 我感觉常见的都是每个连接维护一个timer, 在handler里更新每个连接的idletime;用AfterFunc做个回调检验是否到期,到期了关闭,没到期继续调用AfterFunc 。这样也不需要用单独goroutine定时遍历啊🧐
from arpc.
for循环里调用Recv(), 每个协议包读完之后,会重新进入循环, 再次调用Recv()里的beforeRecv, 之后才会被阻塞, 这样beforeRecv貌似会被调用两次?
不是两次,而是 recv 多少次,就调用多少次。就像 BeforeRecv 的名字一样,就是要在 conn Recv 前调用。但并不是强制用户这样用,所以 beforeRecv 默认是放空的参数
我也不太理解为什么keepAlive要在BeforeRecv里做而不在handler里做😂, 我感觉常见的都是每个连接维护一个timer, 在handler里更新每个连接的idletime;
如果你的handler是指读到一个完整包后的处理函数/handler,那是不可以的,因为如果僵尸连接,根本没机会读到一个完整协议包
用AfterFunc做个回调检验是否到期,到期了关闭,没到期继续调用AfterFunc 。这样也不需要用单独goroutine定时遍历啊🧐
标准库 TCPConn 的 SetDeadline 好像是最终到这里:
https://github.com/golang/go/blob/b357b05b70d2b8c4988ac2a27f2af176e7a09e1b/src/internal/poll/fd_poll_runtime.go#L160
https://github.com/golang/go/blob/b357b05b70d2b8c4988ac2a27f2af176e7a09e1b/src/runtime/netpoll.go#L253
runtime 里的也是timer,但是估计只是超时后原来 Recv 阻塞的协程里直接失败、这是runtime调度就可控的,不需要额外创建一个协程来执行 Close 之类的,而 time.AfterFunc 在超时后的回调是异步、需要创建一个协程,这个成本是不划算的:
https://github.com/golang/go/blob/master/src/time/sleep.go#L167
而且退一步讲,既然 TCPConn 已经提供了 SetDeadline 相关,go 这种一个连接一个协程的同步代码的便利性,也不需要time.AfterFunc那么麻烦
from arpc.
package main
import (
"log"
"net"
"time"
"github.com/lesismal/arpc"
)
func main() {
svr := arpc.NewServer()
svr.Handler.BeforeRecv(func(c net.Conn) error {
log.Printf("BeforeRecv 调用")
return nil
})
svr.Handler.Handle("/echo/sync", func(ctx *arpc.Context) {
str := ""
ctx.Bind(&str)
ctx.Write(str)
})
go func() {
time.Sleep(time.Second)
client, err := arpc.NewClient(func() (net.Conn, error) {
return net.DialTimeout("tcp", "localhost:8888", time.Second*3)
})
req := "hello"
rsp := ""
err = client.Call("/echo/sync", &req, &rsp, time.Second*500)
if err != nil {
log.Printf("Call /echo/sync failed: %v", err)
} else {
log.Printf("Call /echo/sync Response: \"%v\"", rsp)
}
}()
svr.Run("localhost:8888")
}
/*
2021/12/29 00:49:55.560 [INF] [ARPC SVR] Running On: "127.0.0.1:8888"
2021/12/29 00:49:56.560 [INF] [ARPC CLI] 127.0.0.1:8888 Connected
2021/12/29 00:49:56.560 [INF] [ARPC SVR] 127.0.0.1:34924 Connected
2021/12/29 00:49:56 BeforeRecv 调用
2021/12/29 00:49:56 BeforeRecv 调用
2021/12/29 00:49:56 Call /echo/sync Response: "hello"
*/
比如上面的代码, 我觉得在recv结束之后, BeforeRecv 被再次调用了吧.
Line 722 in c3f8d6d
当这个client.Conn不可读的时候, 这个循环会先调用BeforeRecv, 再被阻塞
from arpc.
比如上面的代码, 我觉得在recv结束之后, BeforeRecv 被再次调用了吧.
这有什么问题吗?每次读取完整协议包之前都应该按照当前时间更新deadline,如果只设置一次,比如:
setdeadline(15s)
for {
read
}
这样15s后、不管有没有数据过来,读都会失败。
from arpc.
逻辑上没问题,demo是日志打印顺序的问题,并不是执行顺序的问题,因为拿到Resp并打印比内部for循环跑的晚。
from arpc.
比如上面的代码, 我觉得在recv结束之后, BeforeRecv 被再次调用了吧.
这有什么问题吗?每次读取完整协议包之前都应该按照当前时间更新deadline,如果只设置一次,比如:
setdeadline(15s) for { read }这样15s后、不管有没有数据过来,读都会失败。
哦哦, 是我想错了, 打扰了 新年快乐!
新年快乐!:smile:
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.