[Golang] 从零开始写Socket Server(5):Server的解耦—通过Router+Controller实现逻辑分发

ahlxt123 · · 2896 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

       在实际的系统项目工程中中,我们在写代码的时候要尽量避免不必要的耦合,否则你以后在更新和维护代码的时候会发现如同深陷泥潭,随便改点东西整个系统都要变动的酸爽会让你深切后悔自己当初为什么非要把东西都写到一块去(我不会说我刚实习的时候就是这么干的。。。)

       所以这一篇主要说说如何设计Sever的内部逻辑,将Server处理Client发送信息的这部分逻辑与Sevrer处理Socket连接的逻辑进行解耦~

       这一块的实现灵感主要是在读一个HTTP开源框架: Beego  的源代码的时候产生的,Beego的整个架构就是高度解耦的,这里引用一下作者的介绍:

    beego 是基于八大独立的模块构建的,是一个高度解耦的框架。当初设计 beego 的时候就是考虑功能模块化,用户即使不使用 beego 的 HTTP 逻辑,也依旧可以使用这些独立模块,例如:你可以使用 cache 模块来做你的缓存逻辑;使用日志模块来记录你的操作信息;使用 config 模块来解析你各种格式的文件。所以 beego 不仅可以用于 HTTP 类的应用开发,在你的 socket 游戏开发中也是很有用的模块,这也是 beego 为什么受欢迎的一个原因。大家如果玩过乐高的话,应该知道很多高级的东西都是一块一块的积木搭建出来的,而设计 beego 的时候,这些模块就是积木,高级机器人就是 beego。


       这里上一张Beego的架构图:


     

       这是一个典型的MVC框架,可以看到,当用户发送请求到beego后,Beego内部在通过路由进行参数的过滤,然后路由根据用户发来的参数判断调用哪个Controller执行相关的逻辑,并在controller里调用相关的模块实现功能。通过这种方式,Beego成功的将所有模块都独立出来,也就是astaxie所说的“乐高积木化”。

       在这里,我们可以仿照Beego的架构,在Server内部加入一层Router,通过Router对通过Socket发来的信息进通过我们设定的规则行的判断后,调用相关的Controller进行任务的分发处理。在这个过程中不仅Controller彼此独立,匹配规则和Controller之间也是相互独立的。

       下面给出Router的实现代码,其中Msg的结构对应的是Json字符串,当然考虑到实习公司现在也在用这个,修改了一部分,不过核心思路是一样的哦:

import (
	"utils"
	"fmt"
	"encoding/json"
)

type Msg struct {
	Conditions   map[string]interface{} `json:"meta"`
	Content interface{}            `json:"content"`
}

type Controller interface {
	Excute(message Msg) []byte
}

var routers [][2]interface{}

func Route(judge interface{} ,controller Controller) {
	switch judge.(type) {
	case func(entry Msg)bool:{
		var arr [2]interface{}
		arr[0] = judge
		arr[1] = controller
		routers = append(routers,arr)
	}
	case map[string]interface{}:{
		defaultJudge:= func(entry Msg)bool{
			for keyjudge , valjudge := range judge.(map[string]interface{}){
				val, ok := entry.Meta[keyjudge]
				if !ok {
					return false
				}
				if val != valjudge {
					return false
				}
			}
			return true
		}
		var arr [2]interface{}
		arr[0] = defaultjudge
		arr[1] = controller
		routers = append(routers,arr)
		fmt.Println(routers)
		}
	default:
		fmt.Println("Something is wrong in Router")
	}
}

      通过自定义接口Router,我们将匹配规则judge和对应的controller封装了进去,然后在Server端负责接收socket发送信息的函数handleConnection那里再实现Router内部的遍历即可:

for _ ,v := range routers{
		pred := v[0]
		act := v[1]
		var message Msg
		err := json.Unmarshal(postdata,&message)
		if err != nil {
			Log(err)
		}
		if pred.(func(entry Msg)bool)(message) {
			result := act.(Controller).Excute(message)
			conn.Write(result)
			return
		}
	}

       这样Client每次发来信息,我们就可以让Router自动跟现有的规则进行匹配,最后调用对应的Controller进行逻辑的实现啦,下面给出一个controller的编写实例,这个Controll的作用是发来的json类型是mirror的时候,将Client发来的信息原样返回:

type MirrorController struct  {

}

func (this *MirrorController) Excute(message Msg)[]byte {
	mirrormsg,err :=json.Marshal(message)
	CheckError(err)
	return mirrormsg
}


func init() {
	var mirror 
	routers = make([][2]interface{} ,0 , 20)
	Route(func(entry Msg)bool{
		if entry.Meta["msgtype"]=="mirror"{
		return true}
		return  false
	},&mirror)
}


    

版权声明:本文为博主原创文章,未经博主允许不得转载。


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2896 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传