青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Fork me on GitHub
隨筆 - 215  文章 - 13  trackbacks - 0
<2017年2月>
2930311234
567891011
12131415161718
19202122232425
2627281234
567891011


專注即時通訊及網游服務端編程
------------------------------------
Openresty 官方模塊
Openresty 標準模塊(Opm)
Openresty 三方模塊
------------------------------------
本博收藏大部分文章為轉載,并在文章開頭給出了原文出處,如有再轉,敬請保留相關信息,這是大家對原創作者勞動成果的自覺尊重!!如為您帶來不便,請于本博下留言,謝謝配合。

常用鏈接

留言簿(1)

隨筆分類

隨筆檔案

相冊

Awesome

Blog

Book

GitHub

Link

搜索

  •  

積分與排名

  • 積分 - 220950
  • 排名 - 117

最新評論

閱讀排行榜

http://www.jb51.net/article/80771.htm

Server的解耦—通過Router+Controller實現邏輯分發

在實際的系統項目工程中中,我們在寫代碼的時候要盡量避免不必要的耦合,否則你以后在更新和維護代碼的時候會發現如同深陷泥潭,隨便改點東西整個系統都要變動的酸爽會讓你深切后悔自己當初為什么非要把東西都寫到一塊去(我不會說我剛實習的時候就是這么干的。。。)
所以這一篇主要說說如何設計Sever的內部邏輯,將Server處理Client發送信息的這部分邏輯與Sevrer處理Socket連接的邏輯進行解耦~
這一塊的實現靈感主要是在讀一個HTTP開源框架: Beego  的源代碼的時候產生的,Beego的整個架構就是高度解耦的,這里引用一下作者的介紹:
beego 是基于八大獨立的模塊構建的,是一個高度解耦的框架。當初設計 beego 的時候就是考慮功能模塊化,用戶即使不使用 beego 的 HTTP 邏輯,也依舊可以使用這些獨立模塊,例如:你可以使用 cache 模塊來做你的緩存邏輯;使用日志模塊來記錄你的操作信息;使用 config 模塊來解析你各種格式的文件。所以 beego 不僅可以用于 HTTP 類的應用開發,在你的 socket 游戲開發中也是很有用的模塊,這也是 beego 為什么受歡迎的一個原因。大家如果玩過樂高的話,應該知道很多高級的東西都是一塊一塊的積木搭建出來的,而設計 beego 的時候,這些模塊就是積木,高級機器人就是 beego。 
這里上一張Beego的架構圖:

2016310160604529.png (793×291)


 

  這是一個典型的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) 
}

日志模塊的設計與定時任務模塊模塊
作為一個Server,日志(Log)功能是必不可少的,一個設計良好的日志模塊,不論是開發Server時的調試,還是運行時候的維護,都是非常有幫助的。
因為這里寫的是一個比較簡化的Server框架,因此我選擇對Golang本身的log庫進行擴充,從而實現一個簡單的Log模塊。
在這里,我將日志的等級大致分為Debug,Operating,Error 3個等級,Debug主要用于存放調試階段的日志信息,Operateing用于保存Server日常運行時產生的信息,Error則是保存報錯信息。
模塊代碼如下:
復制代碼 代碼如下:

func LogErr(v ...interface{}) { 
 
    logfile := os.Stdout 
    log.Println(v...) 
    logger := log.New(logfile,"\r\n",log.Llongfile|log.Ldate|log.Ltime); 
    logger.SetPrefix("[Error]") 
    logger.Println(v...) 
    defer logfile.Close(); 

 
func Log(v ...interface{}) { 
 
    logfile := os.Stdout 
    log.Println(v...) 
    logger := log.New(logfile,"\r\n",log.Ldate|log.Ltime); 
    logger.SetPrefix("[Info]") 
    logger.Println(v...) 
    defer logfile.Close(); 

 
func LogDebug(v ...interface{}) { 
    logfile := os.Stdout 
    log.Println(v...) 
    logger := log.New(logfile,"\r\n",log.Ldate|log.Ltime); 
    logger.SetPrefix("[Debug]") 
    logger.Println(v...) 
    defer logfile.Close(); 

 
func CheckError(err error) { 
    if err != nil { 
        LogErr(os.Stderr, "Fatal error: %s", err.Error()) 
    } 

注意這里log的輸出我使用的是stdout,因為這樣在Server運行的時候可以直接將log重定向到指定的位置,方便整個Server的部署。不過在日常開發的時候,為了方便調試代碼,我推薦將log輸出到指定文件位置下,這樣在調試的時候會方便很多(主要是因為golang的調試實在太麻煩,很多時候都要依靠打log的時候進行步進。便于調試的Log模塊代碼示意:
復制代碼 代碼如下:

func Log(v ...interface{}) { 
 
    logfile := os.OpenFile("server.log",os.O_RDWR|os.O_APPEND|os.O_CREATE,0); 
    if err != nil { 
        fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error()) 
        return    } 
    log.Println(v...) 
    logger := log.New(logfile,"\r\n",log.Ldate|log.Ltime); 
    logger.SetPrefix("[Info]") 
    logger.Println(v...) 
    defer logfile.Close(); 

然后就是計時循環模塊啦,日常運行中,Server經常要執行一些定時任務,比如隔一定時間刷新后臺,隔一段時間自動刷新爬蟲等等,在這里我設計了一個Task接口,通過類似于TaskList的的方式將所有定時任務注冊后統一執行,代碼如下:
復制代碼 代碼如下:

type DoTask interface { 
    Excute() 

 
var tasklist []interface{} 
 
func AddTask(controller DoTask) { 
    var arr interface{} 
    arr = controller 
    tasklist = append(tasklist,arr) 
    fmt.Println(tasklist) 
    } 

在這里以一個定時報時任務作為例子:
復制代碼 代碼如下:

type Task1 struct {} 
 
func (this * Task1)Excute() { 
    timer := time.NewTicker(2 * time.Second) 
    for { 
        select { 
        case <-timer.C: 
            go func() { 
                Log(time.Now()) 
            }() 
        } 
    } 

 
func init() { 
    var task1 Task1 
    tasklist = make([]interface{} ,0 , 20) 
    AddTask(&task1) 
        for _, v := range tasklist { 
            v.(DoTask).Excute() 
        } 
 

注意這里的定時任務要做成非阻塞的,否則整個Server都會卡在tasklist的第一個task的。。。

 

 

您可能感興趣的文章:

posted on 2016-08-23 16:36 思月行云 閱讀(168) 評論(0)  編輯 收藏 引用 所屬分類: Golang
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美视频亚洲视频| 久久国产乱子精品免费女| 欧美肥婆在线| 久久精品亚洲精品| 午夜精品一区二区三区在线视| 99re6热只有精品免费观看| 亚洲精品一区在线观看香蕉| 亚洲日本欧美在线| 免费看黄裸体一级大秀欧美| 美女网站在线免费欧美精品| 亚洲高清不卡一区| 亚洲国产精品久久久| 99re热这里只有精品视频| 亚洲桃花岛网站| 亚洲欧美区自拍先锋| 欧美一区二区视频免费观看 | 国产模特精品视频久久久久| 日韩视频在线一区二区| 一区二区三区久久网| 亚洲欧美成人精品| 久久综合中文色婷婷| 欧美日韩亚洲视频一区| 国产伦精品一区二区三区高清| 国产欧美亚洲一区| 亚洲精品国精品久久99热一| 午夜精品国产更新| 女主播福利一区| 亚洲视频www| 牛夜精品久久久久久久99黑人 | 亚洲亚洲精品三区日韩精品在线视频| 性久久久久久久久久久久| 久久久蜜臀国产一区二区| 亚洲人成人一区二区在线观看| 一区二区免费在线观看| 久久精品久久99精品久久| 欧美日韩xxxxx| 1000精品久久久久久久久| 亚洲欧美日韩一区在线观看| 亚洲高清三级视频| 久久不射中文字幕| 国产精品视频yy9099| 亚洲免费高清视频| 免费中文字幕日韩欧美| 新67194成人永久网站| 欧美日韩国产三级| 亚洲欧洲一二三| 老鸭窝毛片一区二区三区| 一本久久a久久免费精品不卡| 久久精品在线免费观看| 国产日韩欧美制服另类| 亚洲欧美另类在线| 亚洲精品国产欧美| 欧美承认网站| 国产亚洲a∨片在线观看| 亚洲视频图片小说| 最新中文字幕一区二区三区| 久久久人成影片一区二区三区| 国产精品系列在线| 亚洲欧美日韩精品综合在线观看| 亚洲第一在线综合网站| 老司机午夜精品视频| 黄色国产精品| 乱码第一页成人| 久久久精品tv| 亚洲第一毛片| 欧美黑人在线播放| 欧美成人黄色小视频| 亚洲国产欧美久久| 亚洲丁香婷深爱综合| 欧美黄色免费网站| 亚洲精品国产系列| 亚洲自拍高清| 雨宫琴音一区二区在线| 久久久久久久久蜜桃| 久久av最新网址| 国产欧美日韩中文字幕在线| 欧美亚洲免费| 久久久免费精品视频| 好吊日精品视频| 欧美护士18xxxxhd| 欧美日韩一卡| 久久成人免费视频| 久久精品视频免费| 亚洲黄色小视频| 亚洲人体1000| 国产精品国产自产拍高清av| 欧美在线精品免播放器视频| 久久久久久精| 亚洲视频导航| 久久国产免费看| 亚洲欧洲三级电影| 一区二区三区欧美| 一区二区亚洲精品国产| 亚洲欧洲精品天堂一级| 国产精品国色综合久久| 老色批av在线精品| 欧美图区在线视频| 蜜桃久久av一区| 国产精品av免费在线观看| 亚洲一区免费| 99精品国产在热久久婷婷| 国产日韩精品视频一区| 亚洲黄色成人| 国内一区二区三区| 99国产精品久久| 激情综合色丁香一区二区| 亚洲卡通欧美制服中文| 国产一区二区三区久久 | 亚洲女性裸体视频| 亚洲欧洲一区二区在线播放| 亚洲婷婷免费| 亚洲精品视频免费观看| 性欧美激情精品| 在线视频一区二区| 老鸭窝91久久精品色噜噜导演| 亚洲综合精品| 欧美精品一区二区三区在线看午夜 | 久久久久久9| 亚洲欧美国产精品专区久久| 免费av成人在线| 久久蜜桃资源一区二区老牛 | 欧美wwwwww| 久久久久9999亚洲精品| 欧美调教vk| 亚洲精品在线看| 最新日韩精品| 久久久久网址| 久热国产精品| 国产欧美日韩一区二区三区在线观看 | 欧美高清在线观看| 久久综合给合久久狠狠狠97色69| 欧美精品一区二区三区四区| 亚洲第一视频网站| 永久久久久久| 久久一区国产| 免费中文字幕日韩欧美| 黄色成人在线网址| 美女图片一区二区| 欧美91精品| 亚洲国产日韩欧美| 免费黄网站欧美| 亚洲成色777777在线观看影院| 在线观看免费视频综合| 久久久久欧美| 亚洲福利电影| 日韩视频精品| 欧美日韩在线观看视频| 99re66热这里只有精品3直播| 99精品视频网| 欧美日韩在线一区二区| 一区二区三区欧美激情| 欧美在线免费观看视频| 国产综合欧美| 免费欧美日韩国产三级电影| 亚洲国产精品va在线看黑人| 亚洲精品影视| 国产精品美腿一区在线看 | 亚洲第一精品久久忘忧草社区| 亚洲国产日韩欧美在线图片| 欧美69wwwcom| 一区二区三区精品视频在线观看| 亚洲欧美日韩一区二区在线| 国产视频一区在线观看| 久久偷窥视频| 亚洲日韩成人| 久久不射网站| 亚洲精品久久久久久下一站| 欧美日韩一区二区免费在线观看| 亚洲色图制服丝袜| 久久婷婷亚洲| 亚洲深夜av| 黑人极品videos精品欧美裸| 欧美成人r级一区二区三区| 亚洲天堂网在线观看| 免费欧美高清视频| 亚洲午夜一区二区| 亚洲第一级黄色片| 亚洲一区日韩在线| 国产欧美一区二区三区国产幕精品| 午夜精品久久久久久久蜜桃app| 欧美在线亚洲综合一区| 亚洲国产日韩精品| 国产欧美日韩在线| 欧美日韩一区在线视频| 欧美一区在线视频| 一本色道久久综合亚洲精品高清| 久久精品久久99精品久久| 夜色激情一区二区| 亚洲电影视频在线| 国产婷婷一区二区| 国产精品sss| 欧美成黄导航| 久久久久久久综合色一本| 亚洲素人一区二区| 亚洲精品美女在线| 免费观看久久久4p| 欧美一级理论片| 亚洲午夜电影| 亚洲精品久久久久| 91久久夜色精品国产九色|