WebSocket 协议本质上是一个基于 TCP 的协议。

为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTTP 请求不同,包含了一些附加头信息,其中附加头信息"Upgrade: WebSocket"表明这是一个申请协议升级的 HTTP 请求,服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的 WebSocket 连接就建立起来了,双方就可以通过这个连接通道自由的传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动的关闭连接。

import ("encoding/json""github.com/gorilla/websocket""net/http"
)// 抽象出需要的数据结构
// ws连接器  数据  管道 // 已经不是http连接,管道传输数据的事情
type connection struct {// ws 连接器ws *websocket.Conn// 管道send chan []byte// 数据data *Data
}// 抽象ws连接器
// 处理ws中的各种逻辑
type hub struct {// connections注册了连接器connections map[*connection]bool// 从服务器发送的信息broadcast chan []byte// 从连接器注册请求register chan *connection// 销毁请求unregister chan *connection
}var user_list = []string{}// 将连接器对象初始化
var h = hub{// connections注册了连接器connections: make(map[*connection]bool),// 从服务器发送的信息broadcast: make(chan []byte),// 从连接器注册请求register: make(chan *connection),// 销毁请求unregister: make(chan *connection),
}// 处理ws的逻辑实现
func (h *hub)run() {// 监听数据管道,在后端不断处理管道数据for true {// 根据不同的数据管道,处理不同的逻辑select {// 注册case c:= <- h.register:// 标志注册了h.connections[c] = true// 组装data数据c.data.Ip = c.ws.RemoteAddr().String()// 更新类型c.data.Type = "handshake"// 更新用户列表c.data.UserList = user_listdata_byte, _ :=json.Marshal(c.data)// 将数据放入到数据管道c.send <- data_byte// 注销case c := <- h.unregister:// 判断map里是否存在要删的数据if _,ok:=h.connections[c];ok{delete(h.connections,c)// 关闭连接管道close(c.send)}case data := <- h.broadcast:// 处理数据流转,将数据同步到所有用户for c :=range h.connections {// 将数据同步select {case c.send <- data:default:// 防止死循环delete(h.connections,c)close(c.send)}}}}
}// 先实现ws的都读和写   (ws的读写实现的是广播)
// ws中写数据
func (c *connection) writer() {// 从管道遍历数据for message := range c.send{c.ws.WriteMessage(websocket.TextMessage, message)}c.ws.Close()
}// ws连接中读数据
func (c *connection) reader() {// 不断读取websocket数据for true {_, message, err := c.ws.ReadMessage()if err != nil {// 读不进数据,将用户移除h.unregister <- cbreak}// 读取数据// 反序列化json.Unmarshal(message,&c.data)// 根据data的type判断该做什么switch c.data.Type {case "login":// 弹出窗口,输入用户名c.data.User = c.data.Contentc.data.From = c.data.User// 登陆后,将用户加入到用户列表user_list = append(user_list, c.data.User)// 每个用户都加载所有登录了的列表c.data.UserList = user_list// 将数据序列化data_byte, _ := json.Marshal(c.data)h.broadcast <- data_byte// 普通用户case "user":c.data.Type = "user"data_byte, _ := json.Marshal(c.data)h.broadcast <- data_bytecase "logout":c.data.Type = "logout"// 用户列表删除user_list = remove(user_list,c.data.User)c.data.UserList = user_listc.data.Content = c.data.User// 数据序列化,让所有用户看到下线了data_byte, _ := json.Marshal(c.data)h.broadcast <- data_byteh.unregister <- c}}
}// 删除用户切片中数据
func remove(slice []string,user string)[]string {// 严谨判断count := len(slice)if count == 0{return slice}if count == 1 && slice[0]==user {return []string{}}// 定义新的返回切片var my_slice = []string{}// 删除传入切片中的指定用户,其他用户放到新的切片for i := range slice {if slice[i] == user && i==count{return slice[:i]}else if slice[i] == user {my_slice = append(slice[:i],slice[i+1:]...)break}}return my_slice
}// 定义一个升级器,将http请求升级为ws请求
var upgrader = &websocket.Upgrader{ReadBufferSize:1024,  // 读的缓冲大小WriteBufferSize: 1024,  // 写的缓冲大小CheckOrigin: func(r *http.Request) bool {  // 跨域访问return true},
}
// ws的回调函数
func wsHandler(w http.ResponseWriter,r *http.Request)  {  // 参数一般都是强求和相应// 1. 获取ws对象ws,err:=upgrader.Upgrade(w,r,nil)if err != nil {return}// 创建连接对象去做事情// 初始化连接对象c := &connection{ws:   ws,send: make(chan []byte,128),data: &Data{},}// 在ws中注册一下h.register <- c// ws将数据读写跑起来go c.writer()c.reader()defer func() {c.data.Type = "logout"// 用户列表删除user_list = remove(user_list,c.data.User)c.data.UserList = user_listc.data.Content = c.data.User// 数据序列化,让所有用户看到XXX下线了data_byte, _ := json.Marshal(c.data)h.broadcast <- data_byteh.unregister <- c}()
}

Go-webSocket实现广播相关推荐

  1. python基于flask-socketio实现WebSocket消息广播(发布订阅模式)——贰

    场景 在应用中可能有一中场景,客户端A只需要发布消息,另一头多个客户端只需要接收客户端A发过来的消息,即发布订阅模式.也可用于大屏展示端,客户端只负责发布推送内容,广播接收端则进行消息接收.因此在fl ...

  2. WebSocket实现广播

    一.什么是WebSocket WebSocket是HTML5一种新的协议,是一种网络通讯协议,该协议最大的特点是:服务器主动可以向客户端推送消息,当然客户端也可以主动向服务器发送信息,是真正的平等双向 ...

  3. SpringBoot集成WebSocket

    一.什么是WebSocket WebSocket是一种网络传输协议,位于OSI模型的应用层.可在单个TCP连接上进行全双工通信,能更好的节省服务器资源和带宽并达到实时通讯. 客户端和服务端只需完成一次 ...

  4. Go 快速起步:创建 WebSocket 服务器(聊天室)

    先了解 WebSocket 协议 和 HTTP 协议一样,WebSocket  协议也建立在 TCP/IP 协议基础上,但不一样的是 HTTP 协议 为单向协议,即只能客户端向服务器请求资源,服务器才 ...

  5. h5直播开发之旅总结

    前言 关于直播,有很多相关技术文章,这里不多说. 作为前端,我们比较关心我们所需要的. 直播的大致流程: APP端调用摄像头 -> 拍摄视频 -> 实时上传视频 -> 服务器端获取视 ...

  6. php微信墙开发,Node.js如何开发微信墙

    这次给大家带来Node.js如何开发微信墙,Node.js开发微信墙的注意事项有哪些,下面就是实战案例,一起来看一下. 验证服务器有效性 接收用户通过微信订阅号发给服务器的消息 解析收到的XML文本消 ...

  7. laravel 5.1 php版本号,发行版本说明 | 序言 | Laravel 5.1 中文文档

    发行版本说明 由 学院君 创建于5年前, 最后更新于 11个月前 版本号 #2 19641 views 23 likes 0 collects 支持政策 LTS版本,比如Laravel 5.1,将会提 ...

  8. H5之直播开发之旅总结

    转自http://www.cnblogs.com/1wen/p/5973468.html 前言 关于直播,有很多相关技术文章,这里不多说. 作为前端,我们比较关心我们所需要的. 直播的大致流程: AP ...

  9. springboot整合websocket实现一对一消息推送和广播消息推送

    springboot基础环境,请参考springboot文档 maven依赖 <dependency><groupId>org.springframework.boot< ...

  10. java websocket广播_使用 Spring 对 Websocket 进行简单的消息广播和单播

    最近在做毕业设计,需要用到 Websocket 实现消息的推送. 在 Spring 官网上查看文档,发现 Spring 对 Websocket 的功能进行了太多扩展,引入了 STOMP 和 Broke ...

最新文章

  1. jsonSuggest插件如何在使用前激活
  2. 滑动窗口,拥塞控制算法
  3. Java8 Stream 函数式接口
  4. python中八进制_在Python中以八进制格式输入数字
  5. 第27月第24天 git pull fetch
  6. 个人信用报告“数字解读”与妙用
  7. python not instance_Python检查类的实例
  8. Oracle 10g 安装教程
  9. 人工智能自动驾驶的意义,人工智能自动驾驶汽车
  10. 什么是3D建模?用到哪些软件?
  11. R语言快速画出ROC曲线和算出可信区间和p值
  12. 违法占耕辅助处理软件
  13. 基于蜜蜂算法的函数寻优及TSP搜索算法
  14. SCL语言----先进先出
  15. Android模拟机设置中文输入法(拼音、手写、笔画等)
  16. 运营商业务系统基于 KubeSphere 的容器化实践
  17. 2020年一线城市程序员工资大调查
  18. PHP与软件破解导学
  19. r语言 精美rda图_R语言RDA分析结果环境因子丢失
  20. mysql oracle clob_MYSQL 转 ORACLE CLOB类型

热门文章

  1. 无法正常启动程序0xc0000142是什么意思?无法正常启动程序0xc0000142该如何解决?
  2. PrinterWriter 类入门
  3. Ubuntu16.04 打不开文件夹解决办法 | killall nautilus的原理 |nautilus命令快速打开文件
  4. 华为无线显示未连接到服务器,华为手机的无线显示功能怎么使用
  5. 头条飞聊呼之欲出,击败微信难,却可能成为下一个Instagram
  6. android软件工程师应具备的素养
  7. Linux citra存档位置,3ds游戏存档在哪个文件夹
  8. 面临公司变相裁员该如何应对
  9. ​Intel 150亿美元买下Mobileye;雅虎原CEO梅耶尔离职了│IoT黑板报
  10. oracle调用apps,oracleEBS 调用 SHELL 的方法