GO语言
01GO基础-001GO语言简介
01GO基础-002语言环境安装
01GO基础-003Go 语言结构
01GO基础-004Go 语言基础语法1
01GO基础-004Go 语言基础语法2
01GO基础-004Go 语言基础语法3
01GO基础-005Go 语言数据类型
01GO基础-006Go 语言变量
01GO基础-007Go 语言常量
01GO基础-008Go 语言运算符
01GO基础-009条件语句
01GO基础-010循环语句
01GO基础-011函数
01GO基础-012变量作用域
01GO基础-013数组
01GO基础-014指针
01GO基础-015结构体
01GO基础-016切片
01GO基础-017范围(Range)
01GO基础-018Map
01GO基础-019递归函数
01GO基础-020类型转换
01GO基础-021接口
01GO基础-022异常处理
01GO基础-023并发
01GO基础-024strings
01GO基础-025可变参数
01GO基础-026接口2
01GO基础-027异常处理2
01GO基础-028sync包详解
01GO基础-029Context
02GO进阶001包
02GO进阶002init()函数
02GO进阶003包的注意点
02GO进阶003使用go module导入本地包
02GO进阶004 time包
02GO进阶005 file操作
02GO进阶006 io操作
02GO进阶007 os包(文件 I/O、文件属性、目录与链接、创建和移除链接)
02GO进阶008复制文件
02GO进阶009断点续传
02GO进阶010 bufio包
02GO进阶011ioutil包
02GO进阶012遍历文件夹
02GO进阶013并发编程介绍
02GO进阶014Goroutine协程
02GO进阶015 GPM
02GO进阶016 runtime包
02GO进阶017 Channel
02GO进阶018 Goroutine池
02GO进阶019 定时器
02GO进阶020 select
02GO进阶021并发安全和锁
02GO进阶022sync
02GO进阶023原子操作
02GO进阶024 GMP原理与调度
02GO进阶025爬虫小案例
02GO进阶026 面向对象-匿名字段
02GO进阶026 面向对象-接口
02GO进阶027网络编程-互联网协议介绍
02GO进阶027网络编程-socket
02GO进阶027网络编程-http编程
02GO进阶027网络编程-websocket编程
02GO进阶028数据操作-MYSQL
02GO进阶028数据操作-REDIS
02GO进阶028数据操作-RTCD
02GO进阶028数据操作-ZOOKEEPER
02GO进阶028数据操作-KAFKA
02GO进阶028数据操作-RabbitMQ
02GO进阶028数据操作-ElasticSearch
02GO进阶028数据操作-NSQ
02GO进阶028数据操作-memcached
02GO进阶028数据操作-GORM
02GO进阶029beego框架-安装
02GO进阶029beego框架-快速入门
02GO进阶029beego框架-MVC架构介绍-controller设计-参数配置
02GO进阶029beego框架-MVC架构介绍-controller设计-路由设置
02GO进阶029beego框架-MVC架构介绍-controller设计-控制器函数
02GO进阶029beego框架-MVC架构介绍-controller设计-XSRF过滤
02GO进阶029beego框架-MVC架构介绍-controller设计-请求数据处理
02GO进阶029beego框架-MVC架构介绍-controller设计-Session控制
02GO进阶029beego框架-MVC架构介绍-controller设计-过滤器
02GO进阶029beego框架-MVC架构介绍-controller设计-Flash数据
02GO进阶029beego框架-MVC架构介绍-controller设计-URL构建
02GO进阶029beego框架-MVC架构介绍-controller设计-多种格式数据输出
02GO进阶029beego框架-MVC架构介绍-controller设计-表单数据验证
02GO进阶029beego框架-MVC架构介绍-controller设计-错误处理
02GO进阶029beego框架-MVC架构介绍-controller设计-日志处理
02GO进阶029beego框架-MVC架构介绍-model设计-概述
02GO进阶029beego框架-MVC架构介绍-model设计-CRUD操作
02GO进阶029beego框架-MVC架构介绍-model设计-高级查询
02GO进阶029beego框架-MVC架构介绍-model设计-原生SQL查询
02GO进阶029beego框架-MVC架构介绍-model设计-构造查询
02GO进阶029beego框架-MVC架构介绍-model设计-事务处理
02GO进阶029beego框架-MVC架构介绍-model设计-模型定义
02GO进阶029beego框架-MVC架构介绍-model设计-命令模式
02GO进阶029beego框架-MVC架构介绍-model设计-测试用例
02GO进阶029beego框架-MVC架构介绍-view设计-beego 模板语法指南
02GO进阶029beego框架-MVC架构介绍-view设计-模板处理
02GO进阶029beego框架-MVC架构介绍-view设计-其他
本文档使用 MrDoc 发布
-
+
首页
02GO进阶027网络编程-websocket编程
## webSocket是什么 WebSocket是一种在单个TCP连接上进行全双工通信的协议 WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据 在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输 需要安装第三方包: cmd中:go get -u -v github.com/gorilla/websocket ## 举个聊天室的小例子 在同一级目录下新建四个go文件connection.go|data.go|hub.go|server.go 运行 ` go run server.go hub.go data.go connection.go` 运行之后执行local.html文件 server.go文件代码 ```go package main import ( "fmt" "net/http" "github.com/gorilla/mux" ) func main() { router := mux.NewRouter() go h.run() router.HandleFunc("/ws", myws) if err := http.ListenAndServe("127.0.0.1:8080", router); err != nil { fmt.Println("err:", err) } } ``` hub.go文件代码 ```go package main import "encoding/json" var h = hub{ c: make(map[*connection]bool), u: make(chan *connection), b: make(chan []byte), r: make(chan *connection), } type hub struct { c map[*connection]bool b chan []byte r chan *connection u chan *connection } func (h *hub) run() { for { select { case c := <-h.r: h.c[c] = true c.data.Ip = c.ws.RemoteAddr().String() c.data.Type = "handshake" c.data.UserList = user_list data_b, _ := json.Marshal(c.data) c.sc <- data_b case c := <-h.u: if _, ok := h.c[c]; ok { delete(h.c, c) close(c.sc) } case data := <-h.b: for c := range h.c { select { case c.sc <- data: default: delete(h.c, c) close(c.sc) } } } } } ``` data.go文件代码 ```go package main type Data struct { Ip string `json:"ip"` User string `json:"user"` From string `json:"from"` Type string `json:"type"` Content string `json:"content"` UserList []string `json:"user_list"` } ``` connection.go文件代码 ```go package main import ( "encoding/json" "fmt" "net/http" "github.com/gorilla/websocket" ) type connection struct { ws *websocket.Conn sc chan []byte data *Data } var wu = &websocket.Upgrader{ReadBufferSize: 512, WriteBufferSize: 512, CheckOrigin: func(r *http.Request) bool { return true }} func myws(w http.ResponseWriter, r *http.Request) { ws, err := wu.Upgrade(w, r, nil) if err != nil { return } c := &connection{sc: make(chan []byte, 256), ws: ws, data: &Data{}} h.r <- c go c.writer() c.reader() defer func() { c.data.Type = "logout" user_list = del(user_list, c.data.User) c.data.UserList = user_list c.data.Content = c.data.User data_b, _ := json.Marshal(c.data) h.b <- data_b h.r <- c }() } func (c *connection) writer() { for message := range c.sc { c.ws.WriteMessage(websocket.TextMessage, message) } c.ws.Close() } var user_list = []string{} func (c *connection) reader() { for { _, message, err := c.ws.ReadMessage() if err != nil { h.r <- c break } json.Unmarshal(message, &c.data) switch c.data.Type { case "login": c.data.User = c.data.Content c.data.From = c.data.User user_list = append(user_list, c.data.User) c.data.UserList = user_list data_b, _ := json.Marshal(c.data) h.b <- data_b case "user": c.data.Type = "user" data_b, _ := json.Marshal(c.data) h.b <- data_b case "logout": c.data.Type = "logout" user_list = del(user_list, c.data.User) data_b, _ := json.Marshal(c.data) h.b <- data_b h.r <- c default: fmt.Print("========default================") } } } func del(slice []string, user string) []string { count := len(slice) if count == 0 { return slice } if count == 1 && slice[0] == user { return []string{} } var n_slice = []string{} for i := range slice { if slice[i] == user && i == count { return slice[:count] } else if slice[i] == user { n_slice = append(slice[:i], slice[i+1:]...) break } } fmt.Println(n_slice) return n_slice } ``` local.html文件代码 ```html <!DOCTYPE html> <html> <head> <title></title> <meta http-equiv="content-type" content="text/html;charset=utf-8"> <style> p { text-align: left; padding-left: 20px; } </style> </head> <body> <div style="width: 800px;height: 600px;margin: 30px auto;text-align: center"> <h1>www.5lmh.comy演示聊天室</h1> <div style="width: 800px;border: 1px solid gray;height: 300px;"> <div style="width: 200px;height: 300px;float: left;text-align: left;"> <p><span>当前在线:</span><span id="user_num">0</span></p> <div id="user_list" style="overflow: auto;"> </div> </div> <div id="msg_list" style="width: 598px;border: 1px solid gray; height: 300px;overflow: scroll;float: left;"> </div> </div> <br> <textarea id="msg_box" rows="6" cols="50" onkeydown="confirm(event)"></textarea><br> <input type="button" value="发送" onclick="send()"> </div> </body> </html> <script type="text/javascript"> var uname = prompt('请输入用户名', 'user' + uuid(8, 16)); var ws = new WebSocket("ws://127.0.0.1:8080/ws"); ws.onopen = function () { var data = "系统消息:建立连接成功"; listMsg(data); }; ws.onmessage = function (e) { var msg = JSON.parse(e.data); var sender, user_name, name_list, change_type; switch (msg.type) { case 'system': sender = '系统消息: '; break; case 'user': sender = msg.from + ': '; break; case 'handshake': var user_info = {'type': 'login', 'content': uname}; sendMsg(user_info); return; case 'login': case 'logout': user_name = msg.content; name_list = msg.user_list; change_type = msg.type; dealUser(user_name, change_type, name_list); return; } var data = sender + msg.content; listMsg(data); }; ws.onerror = function () { var data = "系统消息 : 出错了,请退出重试."; listMsg(data); }; function confirm(event) { var key_num = event.keyCode; if (13 == key_num) { send(); } else { return false; } } function send() { var msg_box = document.getElementById("msg_box"); var content = msg_box.value; var reg = new RegExp("\r\n", "g"); content = content.replace(reg, ""); var msg = {'content': content.trim(), 'type': 'user'}; sendMsg(msg); msg_box.value = ''; } function listMsg(data) { var msg_list = document.getElementById("msg_list"); var msg = document.createElement("p"); msg.innerHTML = data; msg_list.appendChild(msg); msg_list.scrollTop = msg_list.scrollHeight; } function dealUser(user_name, type, name_list) { var user_list = document.getElementById("user_list"); var user_num = document.getElementById("user_num"); while(user_list.hasChildNodes()) { user_list.removeChild(user_list.firstChild); } for (var index in name_list) { var user = document.createElement("p"); user.innerHTML = name_list[index]; user_list.appendChild(user); } user_num.innerHTML = name_list.length; user_list.scrollTop = user_list.scrollHeight; var change = type == 'login' ? '上线' : '下线'; var data = '系统消息: ' + user_name + ' 已' + change; listMsg(data); } function sendMsg(msg) { var data = JSON.stringify(msg); ws.send(data); } function uuid(len, radix) { var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); var uuid = [], i; radix = radix || chars.length; if (len) { for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix]; } else { var r; uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; uuid[14] = '4'; for (i = 0; i < 36; i++) { if (!uuid[i]) { r = 0 | Math.random() * 16; uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; } } } return uuid.join(''); } </script> ```
admin
2024年12月25日 13:30
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码