V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  assiadamo  ›  全部回复第 1 页 / 共 26 页
回复总数  517
1  2  3  4  5  6  7  8  9  10 ... 26  
1 天前
回复了 tog 创建的主题 问与答 有踢脚线取暖器推荐?
搜露营火炉,直接烧柴,架个烟囱,一会屋里就 30 多度了
WebGPU 实时光追美少女[https://zhuanlan.zhihu.com/p/407191699]
MIT 大神
6 天前
回复了 lgapple 创建的主题 问与答 现在平板的家长控制哪家做的比较好
@sodayo 不给键盘,路由器黑名单,我的世界是好游戏,我支持玩,氪金手游就算了,端游一般没键盘就玩不了,把几个云游戏的 domain ban 了就行了
6 天前
回复了 lgapple 创建的主题 问与答 现在平板的家长控制哪家做的比较好
surface pro11 啊,arm windows ,啥也玩不了
我想梳回杀马特头型高唱膤↓哒哪嚒罙 卞棏吶嚒認眞
vless+ws+tls+cf warp 还不优雅
@lloovve 那是阿杜的,寂寞沙洲冷是周传雄的
相似的还有
明明是三个人的电影,我却始终不能有姓名
13 天前
回复了 DIO 创建的主题 Android Java 中可以做到函数嵌套吗
你可以嵌个 nashron js 引擎,java 调用 js 代码。
不过 nashron 支持的 js 语法有限,比如=>就不支持
@sallyliu2024 虾仁猪心
14 天前
回复了 TestOPS 创建的主题 职场话题 大家好,关于我转行矿工的生活
想到黄政民的电影国际市场,不过人家是去西德挖矿挣了好多钱
@sallyliu2024 多邻国连胜 800 多天了,学的英语够竞聘研发吗
@Keuin 我理解了,虽然仍然要在 main 中组装,但基于 interface 的写法更符合 go 的设计一点,我会试试看
@yoyolichen 策略模式就是类型和他的处理函数的 map ,是用上的,Java 和 Go 的区别在于,Java 可以依赖注解在运行时构建,而 Go 只能手动注册或代码生成,总之要在编译器前准备好,运行时虽然可能可以做到,但性能不一定好
@Danswerme 我看前端也是看魔法的,比如 vue 为啥改了 data 里的数据,显示也跟着变了
@xuanbg 互联网行业叫框架,我更喜欢把我做的这套叫引擎...
我想了想图啥呀这么折腾,很多服务器也是静态代码做引擎,业务逻辑和协议处理用脚本语言,比如 go+lua ,cpp+python ,语法糖多还不折腾还好热更,go 服务器热更要用的 plugin 也是很耐人寻味
@NessajCN
少贴了 这是全部
// ========= 通信框架层 ===========
type Msg interface {
Process() error
}

// 注册协议处理函数
type MsgProcessorFunc[T Msg] func(msg T) error

var MsgProcessor = map[int32]MsgProcessorFunc[Msg]{}

// 注册协议创建函数
var MsgCreator = map[int32]func() Msg{}

// ========= 生成的协议类 ===========
type Echo struct {
// TypeId 应该隐藏在 MsgBase 中 此处简略
TypeId int32
Msg string
}

func NewEcho() *Echo {
return &Echo{
TypeId: 1,
}
}

func (echo *Echo) Process() error {
return MsgProcessor[echo.TypeId](echo)
}

// ========= 业务层 ===========
func ProcessEcho(echo *Echo) error {
fmt.Println(echo.Msg)
return nil
}

// 调用例子
func main() {
// 想干掉的手动注册 如果不行只能用代码生成
MsgCreator[1] = func() Msg { return NewEcho() }
MsgProcessor[1] = func(msg Msg) error { return ProcessEcho(msg.(*Echo)) }

// 模拟协议发送
msg := &Echo{TypeId: 1, Msg: "test"}

// 省掉了编解码和 socket 操作

msg.Process()
}
@NessajCN
// 注册协议处理函数
type MsgProcessorFunc[T Msg] func(msg T) error

var MsgProcessor = map[int32]MsgProcessorFunc[Msg]{}

// 注册协议创建函数
var MsgCreator = map[int32]func() Msg{}

// ========= 生成的协议类 ===========
type Echo struct {
// TypeId 应该隐藏在 MsgBase 中 此处简略
TypeId int32
Msg string
}

func NewEcho() *Echo {
return &Echo{
TypeId: 1,
}
}

func (echo *Echo) Process() error {
return MsgProcessor[echo.TypeId](echo)
}

// ========= 业务层 ===========
func ProcessEcho(echo *Echo) error {
fmt.Println(echo.Msg)
return nil
}

// 调用例子
func main() {
// 想干掉的手动注册 如果不行只能用代码生成
MsgCreator[1] = func() Msg { return NewEcho() }
MsgProcessor[1] = func(msg Msg) error { return ProcessEcho(msg.(*Echo)) }

// 模拟协议发送
msg := &Echo{TypeId: 1, Msg: "test"}

// 省掉了编解码和 socket 操作

msg.Process()
}

这是可执行的代码示例
做了很多工作就是为了干掉那两句注册
@leonshaw 对的,如果有注解就不会太纠结
@NessajCN 业务逻辑写在框架外面,这里的框架是通信框架,业务逻辑调用的入口肯定是框架吧。
典型的长链接服务器处理流程:
1. 绑定端口等待链接
2. 从链接获取数据,解析成协议
3. 从协议号获取对应的业务逻辑处理函数,传入协议体
4. 若需要返回结果,也要包装成协议,编码成字节属于,通过链接写回

我认为 go 的设计哲学突出了一个简单,让基于网络层的服务器程序都非常容易实现,所以当然能一把梭全写在一起。但 java 的设计逻辑很不一样,看中抽象复用等很软工的东西,我受毒害很深。
说到软工,分层设计是很有用的思路,上述步骤中 12 应该都是通信层做的事情,协议作为通信层和业务层的桥梁,虽然位置和业务层在一起,但不应该有任何编码行为,比如 protobuf 生成的协议类,注释就有 DO NOT EDIT IT 。
问题也在这里,protobuf 不能自解释,一段数据来了不知道他是什么协议,需要再包一层加上协议号或其他数据,再结合 go 自己的一些特性,比如参数是接口的函数,不接受接口的实现类做入参,ChatGPT 说 Go 不支持协变,我都不知道有这种词,让单纯的写业务逻辑变的艰难,我见过一些框架,直接传入业务层 byte 数组,在业务层做协议编解码,我忍不了这个,所以才折腾这一出。
1  2  3  4  5  6  7  8  9  10 ... 26  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3250 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 27ms · UTC 12:50 · PVG 20:50 · LAX 04:50 · JFK 07:50
Developed with CodeLauncher
♥ Do have faith in what you're doing.