Go语言开发分布式聊天室

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介:

声明

我是一个刚学go语言的菜鸟,还没有资格谈论什么技术分享,只是为了展示fooking的实际应用,同时把我用go写的聊天室代码贴出来供大家消遣,如果有入不了各位法眼的代码,望轻喷。该聊天室基于fooking,而业务代码是采用Go + Fastcgi。

完整的源代码在 https://github.com/scgywx/fooking/blob/master/example/chat/gateway.go ,全代码200多行,去掉router部分代码,实际逻辑代码只有170来行,逻辑简单,功能强大。

详解

聊天服务器的入口main函数里有3个IP和端口配置,分别是Chat服务器、Router服务器和Redis服务器。

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服务器有多简单了。

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-关闭连接),而聊天室只需要关心客户端请求和断开事件。请求可能是登陆、发消息或者是加入频道,而断开事件我们就需要把用户信息删除,并且把他的退出信息广播给所有在聊天室的人。代码如下:

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)。

代码里面的消息广播、用户分频道都是在Router部分实现,他是fooking消息转发与用户数据维持的中间件。

为什么使用FastCGI

其实开发一个聊天室可以很简单,可以直接使用websocket协议,让客户端跟服务器直接通信,简单方便,通信代价低。并且做socket服务也不受协议限制,完全可以自定义或者是使用其它轻量级的协议,比如mqtt什么的。然而为什么要使用fastcgi呢?主要是他的协议实现简单,并且扩展性也非常强,目前世界上最强大的语言php的fpm就是使用该协议与nginx进行通信,如果你的服务使用fastcgi协议开发,那么你可以完美的使用nginx与你的服务进行通信,这样做的好处是写socket服务能像写web服务一样调试,开发完一个功能你只需要简单的执行如下命令即可(当然你可能需要添加少量的代码来判断来源是从nginx还是你自己的客户端)。

curl -d '{"type":"login","name":"xxx"}' 'http://fooking/gateway.php?SESSIONID=aaa&EVENT=0'

网关与逻辑分离另一个好处是,当业务逻辑代码需要更新,客户端毫无察觉的,真正做到无痛更新。另外fastcgi协议本身已经支持多路复用(当然这个需要服务端的支持),这个功能可是大名鼎鼎的http到2.0才支持的哟。

协议详细说明请见:http://www.fastcgi.com/drupal/node/6?q=node/22

为什么使用Fooking

文章开篇已经说了,我是一个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即可

文章转载自 开源中国社区[https://www.oschina.net]

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
存储 监控 算法
员工上网行为监控中的Go语言算法:布隆过滤器的应用
在信息化高速发展的时代,企业上网行为监管至关重要。布隆过滤器作为一种高效、节省空间的概率性数据结构,适用于大规模URL查询与匹配,是实现精准上网行为管理的理想选择。本文探讨了布隆过滤器的原理及其优缺点,并展示了如何使用Go语言实现该算法,以提升企业网络管理效率和安全性。尽管存在误报等局限性,但合理配置下,布隆过滤器为企业提供了经济有效的解决方案。
94 8
员工上网行为监控中的Go语言算法:布隆过滤器的应用
|
2月前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
47 7
|
2月前
|
Go 开发工具
百炼-千问模型通过openai接口构建assistant 等 go语言
由于阿里百炼平台通义千问大模型没有完善的go语言兼容openapi示例,并且官方答复assistant是不兼容openapi sdk的。 实际使用中发现是能够支持的,所以自己写了一个demo test示例,给大家做一个参考。
|
2月前
|
数据管理 API 调度
鸿蒙HarmonyOS应用开发 | 探索 HarmonyOS Next-从开发到实战掌握 HarmonyOS Next 的分布式能力
HarmonyOS Next 是华为新一代操作系统,专注于分布式技术的深度应用与生态融合。本文通过技术特点、应用场景及实战案例,全面解析其核心技术架构与开发流程。重点介绍分布式软总线2.0、数据管理、任务调度等升级特性,并提供基于 ArkTS 的原生开发支持。通过开发跨设备协同音乐播放应用,展示分布式能力的实际应用,涵盖项目配置、主界面设计、分布式服务实现及部署调试步骤。此外,深入分析分布式数据同步原理、任务调度优化及常见问题解决方案,帮助开发者掌握 HarmonyOS Next 的核心技术和实战技巧。
244 76
鸿蒙HarmonyOS应用开发 | 探索 HarmonyOS Next-从开发到实战掌握 HarmonyOS Next 的分布式能力
|
7天前
|
Go C语言
Go语言入门:分支结构
本文介绍了Go语言中的条件语句,包括`if...else`、`if...else if`和`switch`结构,并通过多个练习详细解释了它们的用法。`if...else`用于简单的条件判断;`if...else if`处理多条件分支;`switch`则适用于基于不同值的选择逻辑。特别地,文章还介绍了`fallthrough`关键字,用于优化重复代码。通过实例如判断年龄、奇偶数、公交乘车及成绩等级等,帮助读者更好地理解和应用这些结构。
34 14
|
22小时前
|
监控 Linux PHP
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
41 20
|
2月前
|
程序员 Go
go语言中结构体(Struct)
go语言中结构体(Struct)
124 71
|
2月前
|
存储 Go 索引
go语言中的数组(Array)
go语言中的数组(Array)
121 67
|
21天前
|
存储 监控 算法
内网监控系统之 Go 语言布隆过滤器算法深度剖析
在数字化时代,内网监控系统对企业和组织的信息安全至关重要。布隆过滤器(Bloom Filter)作为一种高效的数据结构,能够快速判断元素是否存在于集合中,适用于内网监控中的恶意IP和违规域名筛选。本文介绍其原理、优势及Go语言实现,提升系统性能与响应速度,保障信息安全。
27 5
|
1月前
|
算法 安全 Go
Go语言中的加密和解密是如何实现的?
Go语言通过标准库中的`crypto`包提供丰富的加密和解密功能,包括对称加密(如AES)、非对称加密(如RSA、ECDSA)及散列函数(如SHA256)。`encoding/base64`包则用于Base64编码与解码。开发者可根据需求选择合适的算法和密钥,使用这些包进行加密操作。示例代码展示了如何使用`crypto/aes`包实现对称加密。加密和解密操作涉及敏感数据处理,需格外注意安全性。
44 14