websocket封装

package edd_socket

    import (
        "time"
        "log"
        "encoding/json"
        "golang.org/x/net/websocket"
    )

    type ws struct {
        coon *websocket.Conn
    }

    //消息体
    type Message struct {
        Data      interface{} `json:"content"`
        Type      string      `json:"type"`
        TimeStamp int64       `json:"time_stamp"`
    }

    //用户体
    type User struct {
        Uid  string
        conn *websocket.Conn
    }

    var (
        member         = make(map[string]*User)
        uidMapWs       = make(map[string]*websocket.Conn)
        groupMapMember = make(map[string][]*User)
    )

    //实例化ws
    func NewWS(wss *websocket.Conn) *ws {
        return &ws{coon: wss}
    }

    //绑定uid和coon
    func (this *ws) BindUid(uid string) {
        client := User{Uid: uid,conn: this.coon}

        member[uid] = &client
        uidMapWs[uid] = this.coon
    }

    //是否在线
    func (this *ws) IsOnline(uid string) bool {
        _, exits := member[uid]
        return exits
    }

    //断开连接
    func (this *ws) CloseUid(uid string) {
        msg := Message{
            Data: "离开房间",
            Type: "del_user",
        }
        this.SendToAll(msg)

        delete(member, uid)
        delete(uidMapWs, uid)
        this.coon.Close()
    }

    //群发消息
    func (this *ws) SendToAll(msg Message) {
        msg.TimeStamp = time.Now().Unix()
        sendMess, _ := json.Marshal(msg)

        for k, v := range member {
            if v.conn != this.coon {
                if err := websocket.Message.Send(v.conn, string(sendMess)); err != nil {
                    delete(member, k)
                    delete(uidMapWs, k)
                    continue
                }
            }
        }
    }

    //获取当前组人数
    func (this *ws) GetClientCountByGroup(groupName string) int {
        return len(groupMapMember[groupName])
    }

    func (this *ws) GetClientByGroup(groupName string) []*User {
        return groupMapMember[groupName]
    }

    //加入某个群
    func (this *ws) JoinGroup(groupName, uid string) {
        groupMapMember[groupName] = append(groupMapMember[groupName], member[uid])
    }

    //给指定群发消息
    func (this *ws) SendToGroup(groupName string, msg Message) {
        msg.TimeStamp = time.Now().Unix()
        sendMess, _ := json.Marshal(msg)

        for k, v := range groupMapMember[groupName] {
            if v.conn != this.coon {
                if err := websocket.Message.Send(v.conn, string(sendMess)); err != nil {
                    kk := k + 1
                    groupMapMember[groupName] = append(groupMapMember[groupName][:k], groupMapMember[groupName][kk:]...)
                    continue
                }
            }
        }
    }

    //离开某个群
    func (this *ws) LeaveGroup(groupName, uid string) {
        for k, v := range groupMapMember[groupName] {
            if v.Uid == uid {
                kk := k + 1
                groupMapMember[groupName] = append(groupMapMember[groupName][:k], groupMapMember[groupName][kk:] ...)
                break
            }
        }
    }

    //发送给指定uid
    func (this *ws) SendToUid(uid string, msg Message) {
        toWsCoon := uidMapWs[uid]
        msg.TimeStamp = time.Now().Unix()
        sendMess, _ := json.Marshal(msg)

        if err := websocket.Message.Send(toWsCoon, string(sendMess)); err != nil {
            delete(member, uid)
            log.Println(err)
        }
    }

    //解析客户端消息
    func (this *ws) GetMsg(msg *Message) error {
        var reply string
        var err error
        if err = websocket.Message.Receive(this.coon, &reply); err == nil {
            json.Unmarshal([]byte(reply), msg)
        }
        return err
    }

使用:

package edd_socket

import (
    "fmt"
    "net/http"
    "crypto/md5"
    "encoding/hex"
    "io"
    "crypto/rand"
    "encoding/base64"
    "log"
    "golang.org/x/net/websocket"
)

//获取MD5字符串
func getMd5String(s string) string {
    h := md5.New()
    h.Write([]byte(s))
    return hex.EncodeToString(h.Sum(nil))
}

//用于将当前用户信息和当前websocket.conn关联
//正式上线,可用数据库用户Id代替
func getUid() string {
    b := make([]byte, 48)
    if _, err := io.ReadFull(rand.Reader, b); err != nil {
        return ""
    }

    return getMd5String(base64.URLEncoding.EncodeToString(b))
}

func Echo(ws *websocket.Conn) {
    wss := NewWS(ws)
    uid := getUid()

    defer func() {
        wss.CloseUid(uid)
    }()

    for {
        var mess Message
        if err := wss.GetMsg(&mess); err != nil {
            //若当前socket接收不到消息,则已掉线,主动退出for
            fmt.Println(err)
            break
        }

        switch mess.Type {
        case "connect":
            //连接准备,客户端标识符name和服务端标识符绑定
            wss.BindUid(uid)
            msg := Message{
                Data: mess.Data,
                Type: "join_room",
            }

            wss.SendToAll(msg)
        case "all":
            //群发
            msg := Message{
                Data: mess.Data,
                Type: "send_all",
            }
            wss.SendToAll(msg)
        case "join_group":
            //wss.JoinGroup("one", uid)
        case "who":
        }
    }
}

func main() {
    var port = "8022"
    fmt.Println("listening port:" + port)

    go func() {
        http.Handle("/chat", websocket.Handler(Echo))
    }()

    if err := http.ListenAndServe(":"+port, nil); err != nil {
        log.Fatal("ListenAndServer: ", err)
    }
}

客户端

  var ws =new WebSocket(websocket_domain)
    ws.onopen = function (res) {
        ws.send(sendMessAll(name,"进入房间",'connect'))
    };

    ws.onmessage = function (res) {
        var data = jQuery.parseJSON(res.data);
    };
ws.onclose = function (res) {
        console.log(res)
};
function sendMessAll(name, data, type) {
    return JSON.stringify(
        {
            data: JSON.stringify({
                name:name,
                age:123
            }),
            type: type
        }
    )
}

欢迎指正我的开源地址

3 个评论

这个是聊天室的练习题,和websocket封装有啥关系?没看明白
websocket难道就只能聊天吗?我觉得你真逗
可能我没有表达清楚,按标题《websocket封装》来看,文章的内容应该是封装了websocket,类似github.com/gorilla/websocket 这样的websocket封装。

要回复文章请先登录注册