golang websocket

15 篇文章 0 订阅

理论

WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。而且没有同源策略的限制,不存在跨域问题。协议的标识符就是ws。像https一样如果加密的话就是wxs

 

参考资料

https://blog.csdn.net/yjp19871013/article/details/83444148

https://www.cnblogs.com/lanyangsh/p/9190296.html

https://www.cnblogs.com/bener/p/10717466.html

仅做个人笔记,浏览请看原博主原文

 

golang.org/x/net/websocket

https://godoc.org/golang.org/x/net/websocket

 

连接1

该Server能够处理两个请求

/请求,这是Web项目的根路径,index函数作为处理方法,返回首页index.html。

/upper请求,该请求的处理函数是一个WebSocket的处理函数,它包裹了我们自己定义的upper函数,upper函数有一个参数,就是服务端创建好的WebSocket连接,upper函数逻辑很简单,通过WebSocket连接读取服务器的请求内容,将内容转化为大写后,通过WebSocket将结果返回给客户端。


package main
 
import (
	"fmt"
	"html/template"
	"net/http"
	"os"
	"strings"
	"golang.org/x/net/websocket"
)

//处理ws请求
func upper(ws *websocket.Conn) {
	var err error
	for {
		var reply string
 
		if err = websocket.Message.Receive(ws, &reply); err != nil {
			fmt.Println(err)
			continue
		}
 
		if err = websocket.Message.Send(ws, strings.ToUpper(reply)); err != nil {
			fmt.Println(err)
			continue
		}
	}
}

//处理http请求 
func index(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		return
	}
 
	t, _ := template.ParseFiles("index.html")
	t.Execute(w, nil)
}
 
func main() {
    //ws连接
	http.Handle("/upper", websocket.Handler(upper))

    //http连接
	http.HandleFunc("/", index)
 
	if err := http.ListenAndServe(":9999", nil); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

 

连接2

package main

import (  
    "golang.org/x/net/websocket" 
    "net/http"  
)

func Echo(ws *websocket.Conn) {  
    var err error  
    for {  
        var reply string  

        //websocket接受信息  
        if err = websocket.Message.Receive(ws, &reply); err != nil {  
            fmt.Println("receive failed:", err)  
            break  
        }

        fmt.Println("reveived from client: " + reply)
        msg := "received:" + reply
        fmt.Println("send to client:" + msg)

        //这里是发送消息
        if err = websocket.Message.Send(ws, msg); err != nil {
            fmt.Println("send failed:", err)
            break
        }
    }
}

func main() {
    //接受websocket的路由地址
    http.Handle("/websocket", websocket.Handler(Echo))
}

 

函数

// websocket connection manager
type ConnManager struct {
    // websocket connection number
    Online *int32
    // websocket connection
    connections *sync.Map
}

上面定义了一个连接管理结构体,Online为在线的人数,connections为客户端的连接管理(key为userId,value为websocket connection)。
下面为ConnManager添加一些方法来处理连接、断开连接、发送消息、广播等操作。

// add websocket connection
// online number + 1
func (m *ConnManager) Connected(k, v interface{}) {
    m.connections.Store(k, v)  //存储已连接用户的wsconn 以备后面对指定用户推送消息

    atomic.AddInt32(m.Online, 1)
}

// remove websocket connection by key
// online number - 1
func (m *ConnManager) DisConnected(k interface{}) {
    m.connections.Delete(k)

    atomic.AddInt32(m.Online, -1)
}

// get websocket connection by key
func (m *ConnManager) Get(k interface{}) (v interface{}, ok bool) {
    return m.connections.Load(k)
}

// iter websocket connections
func (m *ConnManager) Foreach(f func(k, v interface{})) {
    m.connections.Range(func(k, v interface{}) bool {
        f(k, v)
        return true
    })
}

// send message to one websocket connection
func (m *ConnManager) Send(k string, msg *Message) {
    v, ok := m.Get(k)  //对指定用户推送消息

    // 注:
    // 对指定用户推送消息,需要当前用户之前必须在登录服登录,我们才能记录他的wsconn,广播也是对这些在线用户发送消息
    
    if ok {
        if conn, ok := v.(*websocket.Conn); ok {
            if err := websocket.JSON.Send(conn, msg); err != nil {
                fmt.Println("Send msg error: ", err)
            }
        } else {
            fmt.Println("invalid type, expect *websocket.Conn")
        }
    } else {
        fmt.Println("connection not exist")
    }
}

// send message to multi websocket connections
func (m *ConnManager) SendMulti(keys []string, msg interface{}) {
    for _, k := range keys {
        v, ok := m.Get(k)
        if ok {
            if conn, ok := v.(*websocket.Conn); ok {
                if err := websocket.JSON.Send(conn, msg); err != nil {
                    fmt.Println("Send msg error: ", err)
                }
            } else {
                fmt.Println("invalid type, expect *websocket.Conn")
            }
        } else {
            fmt.Println("connection not exist")
        }
    }
}

// broadcast message to all websocket connections otherwise own connection
func (m *ConnManager) Broadcast(conn *websocket.Conn, msg *Message) {
    m.Foreach(func(k, v interface{}) {
        if c, ok := v.(*websocket.Conn); ok && c != conn {
            if err := websocket.JSON.Send(c, msg); err != nil {
                fmt.Println("Send msg error: ", err)
            }
        }
    })
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值