美文网首页
架构学习之路(四)-- IM系统初探

架构学习之路(四)-- IM系统初探

作者: 魔改谢馒头 | 来源:发表于2018-09-03 07:35 被阅读0次

之前学习HTTP和TCP请求的时候经常看到一个名词就是长连接,之前一直很好奇怎么去实现,最近偶尔看到一篇文章写的IM系统,想转载学习一下。

IM系统,那么必然需要TCP长连接来维持,由于Golang本身的基础库和外部依赖库非常之多,我们可以简单引用基础net网络库,来建立TCP server。一般的TCP Server端的模型,可以有一个协程【或者线程】去独立执行accept,并且是for循环一直accept新的连接,如果有新连接过来,那么建立连接并且执行Connect,由于Golang里面协程的开销非常之小,因此,TCP server端还可以一个连接一个goroutine去循环读取各自连接链路上的数据并处理。当然, 这个在C++语言的TCP Server模型中,一般会通过EPoll模型来建立server端,这个是和C++的区别之处。
关于读取数据,Linux系统有recv和send函数来读取发送数据,在Golang中,自带有io库,里面封装了各种读写方法,如io.ReadFull,它会读取指定字节长度的数据
为了维护连接和用户,并且一个连接一个用户的一一对应的,需要根据连接能够找到用户,同时也需要能够根据用户找到对应的连接,那么就需要设计一个很好结构来维护。我们最初采用map来管理,但是发现Map里面的数据太大,查找的性能不高,为此,优化了数据结构,conn里面包含user,user里面包含conn,结构如下【只包括重要字段】。

// 一个用户对应一个连接
type User struct {
    uid               int64
    conn              *MsgConn
    BKicked           bool // 被另外登陆的一方踢下线
    BHeartBeatTimeout bool // 心跳超时
}

type MsgConn struct {
    conn       net.Conn
    lastTick   time.Time // 上次接收到包时间
    remoteAddr string    // 为每个连接创建一个唯一标识符
    user       *User     // MsgConn与User一一映射
}

建立TCP server 代码片段如下

func ListenAndServe(network, address string) {
    tcpAddr, err := net.ResolveTCPAddr(network, address)
    if err != nil {
        logger.Fatalf(nil, "ResolveTcpAddr err:%v", err)
    }
    listener, err = net.ListenTCP(network, tcpAddr)
    if err != nil {
        logger.Fatalf(nil, "ListenTCP err:%v", err)
    }
    go accept()
}

func accept() {
    for {
        conn, err := listener.AcceptTCP()
        if err == nil {

            // 包计数,用来限制频率

            //anti-attack, 黑白名单


            // 新建一个连接
            imconn := NewMsgConn(conn)

            // run
            imconn.Run()
        } 
    }
}


func (conn *MsgConn) Run() {

    //on connect
    conn.onConnect()

    go func() {
        tickerRecv := time.NewTicker(time.Second * time.Duration(rateStatInterval))
        for {
            select {
            case <-conn.stopChan:
                tickerRecv.Stop()
                return
            case <-tickerRecv.C:
                conn.packetsRecv = 0
            default:

               // 在 conn.parseAndHandlePdu 里面通过Golang本身的io库里面提供的方法读取数据,如io.ReadFull
                conn_closed := conn.parseAndHandlePdu()
                if conn_closed {
                    tickerRecv.Stop()
                    return
                }
            }
        }
    }()
}

// 将 user 和 conn 一一对应起来
func (conn *MsgConn) onConnect() *User {
    user := &User{conn: conn, durationLevel: 0, startTime: time.Now(), ackWaitMsgIdSet: make(map[int64]struct{})}
    conn.user = user
    return user
}

相关文章

  • 架构学习之路(四)-- IM系统初探

    之前学习HTTP和TCP请求的时候经常看到一个名词就是长连接,之前一直很好奇怎么去实现,最近偶尔看到一篇文章写的I...

  • 消息系统架构学习分享

    文章链接 现代IM系统中的消息系统架构 - 架构篇 现代IM系统中的消息系统架构 - 模型篇 现代IM系统中的消息...

  • iOS 移动端架构初探心得

    iOS 移动端架构初探心得 iOS 移动端架构初探心得

  • 系统架构初探

    先占个坑

  • 系统架构初探

    第一篇文章好兴奋,好兴奋~ 开题: 架构这东西,对于我这种一直在单个服务器上写程序的小白来说一直觉得非常高大上,想...

  • 架构之路

    1. 架构之路 (一) —— iOS原生系统架构(一)2. 架构之路 (二) —— APP架构分析(一)3. 架构...

  • 秒杀业务架构优化之路

    转载:秒杀业务架构优化之路 一、秒杀业务为什么难做 im系统,例如qq或者微博,每个人都读自己的数据(好友列表、群...

  • Kubernetes 系统架构初探\简单介绍

    Kubernetes 系统架构初探\简单介绍 一、前言 by Urs Hölzle, Google 翻译出来的意思...

  • iOS学习笔记(三)——iOS系统架构

    iOS学习笔记(三)——iOS系统架构 iOS的系统架构分为四个层次:核心操作系统层(Core OS layer)...

  • IM - 系统架构设计

    1. 概述 IM系统架构设计,如下图,主要分为两部分: 云盘系统Cpan(蓝色部分)。为了兼容已有云盘系统,提供W...

网友评论

      本文标题:架构学习之路(四)-- IM系统初探

      本文链接:https://www.haomeiwen.com/subject/suymwftx.html