我是一个刚学go语言的菜鸟,尚未资格谈论什么技术分享,只是为了展现fooking的实际应用,同时把我用go写的聊天室代码贴出来供你们消遣,若是有入不了各位法眼的代码,望轻喷。该聊天室基于fooking,而业务代码是采用Go + Fastcgi。php
完整的源代码在 https://github.com/scgywx/fooking/blob/master/example/chat/gateway.go,全代码200多行,去掉router部分代码,实际逻辑代码只有170来行,逻辑简单,功能强大。html
聊天服务器的入口main函数里有3个IP和端口配置,分别是Chat服务器、Router服务器和Redis服务器。node
func main() { listener, _ := net.Listen("tcp", "0.0.0.0:9001")//Chat服务器配置 srv := newChatServer("test:9010", "test:6379");//Router配置与Redis配置 fcgi.Serve(listener, srv) }
Chat服务器就是实现主要的聊天逻辑,Router服务器是用于转发消息,Redis用来存储用户信息。上面我讲过这个聊天室是基于fooking,因此客户端不是直接与go通讯,而是透过fooking来访问的。咱们使用go内置的fastcgi模块来建立一个服务,而后处理请求便可,这跟http服务器很是像,只是协议规范不一样而已,看下面的代码就你知道建立一个fastcgi服务器有多简单了。python
func (s *ChatServer) ServeHTTP(rep http.ResponseWriter, req *http.Request) { //短链接要调用一下这个,不然go不会主动断开链接 //req.ParseForm(); req.Form = make(url.Values); body, e := ioutil.ReadAll(req.Body) if e != nil { fmt.Printf("read request error\n") }else{ sessionid := req.Header.Get("SESSIONID") event := req.Header.Get("EVENT") fmt.Printf("sid=%s, event=%s\n", sessionid, event); //具体的业务逻辑处理 } }
代码中的sessionid就是当前发送请求的客户端ID,当咱们要作一些uid与客户端id映射或者是要发消息给指定用户的时候就可使用这个ID。event就是当前请求的事件类型(0-表示请求,1-新链接,2-关闭链接),而聊天室只须要关心客户端请求和断开事件。请求多是登录、发消息或者是加入频道,而断开事件咱们就须要把用户信息删除,而且把他的退出信息广播给全部在聊天室的人。代码以下:
nginx
switch event { case "1"://新链接 //TODO case "2"://链接关闭 s.logout(sessionid) default://消息处理 if len(body) > 0 { js, err := simplejson.NewJson(body) if err != nil { fmt.Printf("parse JSON error, data=") fmt.Println(body) }else{ r := s.handle(sessionid, js) if len(r) > 0 { rep.Header().Add("Content-Length", strconv.Itoa(len(r))) rep.Write(r) }else{ fmt.Println("no message response") } } } } func (s *ChatServer) handle(sid string, req *simplejson.Json) []byte{ t, _ := req.Get("type").String() switch t { case "login": //登录 ..... case "join": //加入房间 .... case "msg": //发送消息 ..... default: fmt.Printf("invalid type") } return []byte("") }
在上面的消息处理部分,有两句rep.Header().Add和rep.Write,这表示若是须要返回数据给当前发请求的客户端,能够添加Content-Length头(表示要返回给客户端的数据长度),而后调用rep.Write发送数据(相似Http的Request对应一个Response)。git
代码里面的消息广播、用户分频道都是在Router部分实现,他是fooking消息转发与用户数据维持的中间件。github
其实开发一个聊天室能够很简单,能够直接使用websocket协议,让客户端跟服务器直接通讯,简单方便,通讯代价低。而且作socket服务也不受协议限制,彻底能够自定义或者是使用其它轻量级的协议,好比mqtt什么的。然而为何要使用fastcgi呢?主要是他的协议实现简单,而且扩展性也很是强,目前世界上最强大的语言php的fpm就是使用该协议与nginx进行通讯,若是你的服务使用fastcgi协议开发,那么你能够完美的使用nginx与你的服务进行通讯,这样作的好处是写socket服务能像写web服务同样调试,开发完一个功能你只须要简单的执行以下命令便可(固然你可能须要添加少许的代码来判断来源是从nginx仍是你本身的客户端)。
web
curl -d '{"type":"login","name":"xxx"}' 'http://fooking/gateway.php?SESSIONID=aaa&EVENT=0'
网关与逻辑分离另外一个好处是,当业务逻辑代码须要更新,客户端毫无察觉的,真正作到无痛更新。另外fastcgi协议自己已经支持多路复用(固然这个须要服务端的支持),这个功能但是大名鼎鼎的http到2.0才支持的哟。redis
协议详细说明请见:http://www.fastcgi.com/drupal/node/6?q=node/22shell
文章开篇已经说了,我是一个Go语言的初学者,到这里来不是为了秀go技,而是为了展现fooking与各语言的衔接。那么为何要使用fooking?我相信不少人都知道网关这个东西(可能在游戏领域应用的更普遍一些),他其主要的目的是用于承载客户端的链接,把消息转发与业务逻辑分开,后端开发人员只须要专心写逻辑便可。这就比如咱们写web的时候,历来不须要本身去实现http server。那么fooking也是这样一个开源软件,他将socket服务变的更简单。更多的特性以下:
1 动态网关添加.
2 每一个客户端惟一SessionID.
3 组播(相似redis的pub/sub).
4 服务器状态监控.
5 客户端事件通知(如:新链接、关闭链接).
6 后端无语言限制(php, python, go, nodejs, etc...).
7 自定义消息协议.
8 后端长链接维持.
fooking的详细介绍请参见: https://github.com/scgywx/fooking 或者 http://git.oschina.net/scgywx/fooking
第一步(下载和编译)
git clone https://github.com/scgywx/fooking.git
cd {$FOOKING_PATH}
make
第二步(启动Router)
cd src
./fooking ../router.lua
第三步(启动Gateway)
./fooking ../config.lua
第四步(启动Chat服务器)
go run gateway.go
第五步(测试) 修改example/chat/index.html文件的Websocket的服务器IP和端口(查找ws://)
而后用浏览器打开index.html便可