go网络编程-websocket
1. WebSocket编程
文章目录
- 1. WebSocket编程
- 1.1.1. webSocket是什么
- 1.1.2. 举个聊天室的小例子
- server.go文件代码
- hub.go文件代码
- data.go文件代码
- local.html文件代码
1.1.1. webSocket是什么
WebSocket是一种在单个TCP连接上进行全双工通信的协议
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据
在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输
需要安装第三方包:
cmd中:go get -u -v github.com/gorilla/websocket
1.1.2. 举个聊天室的小例子
注意:
这里需要在terminal同时运行四个go文件

在同一级目录下新建四个go文件connection.go|data.go|hub.go|server.go
运行
go run server.go hub.go data.go connection.go
运行之后执行local.html文件
server.go文件代码
package mainimport ("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文件代码
package mainimport "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]boolb chan []byter chan *connectionu chan *connection
}func (h *hub) run() {for {select {case c := <-h.r:h.c[c] = truec.data.Ip = c.ws.RemoteAddr().String()c.data.Type = "handshake"c.data.UserList = user_listdata_b, _ := json.Marshal(c.data)c.sc <- data_bcase 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文件代码
package maintype 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文件代码
package mainimport ("encoding/json""fmt""net/http""github.com/gorilla/websocket"
)type connection struct {ws *websocket.Connsc chan []bytedata *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 <- cgo c.writer()c.reader()defer func() {c.data.Type = "logout"user_list = del(user_list, c.data.User)c.data.UserList = user_listc.data.Content = c.data.Userdata_b, _ := json.Marshal(c.data)h.b <- data_bh.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 <- cbreak}json.Unmarshal(message, &c.data)switch c.data.Type {case "login":c.data.User = c.data.Contentc.data.From = c.data.Useruser_list = append(user_list, c.data.User)c.data.UserList = user_listdata_b, _ := json.Marshal(c.data)h.b <- data_bcase "user":c.data.Type = "user"data_b, _ := json.Marshal(c.data)h.b <- data_bcase "logout":c.data.Type = "logout"user_list = del(user_list, c.data.User)data_b, _ := json.Marshal(c.data)h.b <- data_bh.r <- cdefault: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文件代码
<!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>
多开几个网页就可以呀聊天
相关文章:
go网络编程-websocket
1. WebSocket编程 文章目录1. WebSocket编程1.1.1. webSocket是什么1.1.2. 举个聊天室的小例子server.go文件代码hub.go文件代码data.go文件代码local.html文件代码1.1.1. webSocket是什么 WebSocket是一种在单个TCP连接上进行全双工通信的协议 WebSocket使得客户端和服务器之…...
Microsoft designer 使用教程
继各种ai绘图软件诞生之后 dell 2 playground.... 微软自己研发的重量级产品 Microsoft designer 上线了 Microsoft Designer 是微软公司推出的一款设计工具,主要用于快速创建Web和移动应用程序的原型设计。它提供了一系列的工具和模板,可以帮助用户…...
《Docker系列》Docker容器修改配置文件后,重启失败,如何修改配置并启动容器?
Docker容器修改配置文件后,重启失败,如何修改配置并启动容器? docker部署的MySQL容器,修改了my.cnf配置文件,重启的时候导致无法启动 通过查日志发现,配置文件中的binlog-db-dbhw写错了,应该是…...
遇到多个构造器参数时要考虑使用构建器
静态工厂和构造器有个共同的局限性:他们都不能很好地扩展到大量的可选参数。比如用一个类表示包装食品外面显示的营养成分标签(包括必选域和可选域)。 重叠构造器 对于这样的类一般习惯采用重叠构造器(telescoping constructor&…...
【Storm】【五】Storm集成Kafka
Storm集成Kafka 一、整合说明二、写入数据到Kafka三、从Kafka中读取数据一、整合说明 Storm 官方对 Kafka 的整合分为两个版本,官方说明文档分别如下: Storm Kafka Integration : 主要是针对 0.8.x 版本的 Kafka 提供整合支持;Storm Kafka …...
GVRP-LNP-VCMP讲解
目录 GVRP讲解 动态创建Vlan并将端口加入Vlan GVRP消息类型 GVRP工作原理 LNP讲解 动态修改接口链路类型 VCMP讲解 动态创建Vlan 相关概念 Vlan同步 VCMP与GVRP的区别 GVRP讲解 动态创建Vlan并将端口加入Vlan GVRP(GARR Vlan Registration Protocol…...
28个精品Python爬虫实战项目
先来说说Python的优势!然后给大家看下这28个实战项目的实用性!Python跟其他语言相比,有以下优点:1. 简单Python是所有编程语言里面,代码量最低,非常易于读写,遇到问题时,程序员可以把…...
相信人还是相信ChatGPT,龙测首席AI专家给出了意料之外的答案
最近,关于ChatGPT的话题太火了!各大社交软件都是他的消息!从去年12月份ChatGPT横空出世,再到近期百度文心一言、复旦Moss的陆续宣布,点燃了全球对AIGC(内容人工智能自动生成)领域的热情…...
安卓逆向_5 --- jeb 和 AndroidStudio 动态调试 smali
Jeb 工具的使用 :https://www.52pojie.cn/forum.php?modviewthread&tid742250:https://zhuanlan.zhihu.com/p/302856081动态调试 smali 有两种方法: Jeb 调试AndroidStudio smalidea 插件动态调试。1、Jeb 动态调试 smali JEB是一个…...
docker-容器命令
1.新建启动 docker run options image command [arg..] options: --name"容器新名字" -d:后台运行程序 -it:交互式运行 -P: 随机端口 -p: 指定端口 docker run -it ubuntu /bin/bash docker run -it ubuntu:v1 /bin/bash docker run -it 1c352…...
Spring——是什么?作用?内容?用到的设计模式?
目录 什么是spring? spring是为了解决什么问题而衍生的?(历史)Spring解决了实际生产中的什么问题? spring包含了哪些部分?(组成) Spring的特点是什么? spring框架中…...
Qt交叉编译环境搭建
环境及版本: 编译机:Deepin 20.3 Qt 5.12.9 arm编译工具: gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf.tar.xz 运行机:创龙335X开发板 1.下载arm编译工具: gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-…...
Java switch case 语句
Java 的 switch case 语句是一种常用的控制流语句,用于基于不同的输入值执行不同的操作。本文将详细介绍 Java switch case 语句的作用、用法以及在实际工作中的应用。 一、switch case 语句的作用 switch case 语句是一种多分支条件语句,它基于不同的输…...
Linux下MQTT客户端消息订阅与发布实现
MQTT(消息队列遥测传输)是一个基于客户端-服务器的消息发布/订阅传输协议。它基于TCP协议,默认端口号为1883,为此,它也需要一个消息中间件 。MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛。在很多情况下…...
代码规范----编程规约(下)
目录 四、OOP规约 五、日期时间 六、集合处理 四、OOP规约 (1)、避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,直接用类名来访问即可 (2)、所有的覆写方法࿰…...
c++连接mysql
开始想用mysql connector/c8.0 来操作数据库cmake加上配置后一直编译错误 我这里也没有截屏编译错误大概意思是driver.h里面声明的一个check_lib函数里面用了一个未定义的check找遍了资料都没有找到解决办法最后还是用了原始API如果有人有解决办法请留个位置先上在用的cmake配置…...
CentOS7操作系统安装nginx实战(多种方法,超详细)
文章目录前言一. 实验环境二. 使用yum安装nginx2.1 添加yum源2.1.1 使用官网提供的源地址(方法一)2.1.2 使用epel的方式进行安装(方法二)2.2 开始安装nginx2.3 启动并进行测试2.4 其他的一些用法:三. 编译方式安装ngin…...
【测绘程序设计】——空间直角坐标转换
测绘工程中经常遇到空间直角坐标转换——比如,北京54(或西安80)空间直角坐标转换成CGCS2000(或WGS-84)空间直角坐标,常用转换模型包括:①布尔沙模型(国家级及省级范围);②莫洛坚斯基模型(省级以下范围);③三维四参数(小于22局部区域) 等。 本文分享了基于布…...
数组--java--动态数组--有序数组--底层
java数组基础--java中的数组创建数组空间占用初始化数组访问元素插入查找删除元素动态数组扩容插入和添加重写toString删除二维数组二维数组注意点有序数组实现测试写在开头: 这篇文章包括数组的基础、一点底层的内容和一些稍微深入的东西。 作为第一个深入学习的数…...
Linux下使用C语言实现简单的聊天室程序
本文章介绍一种基于Linux使用C语言实现简单的局域网聊天室程序的方法,支持消息群发,历史数据查询,好友列表查看,好友上线下线提醒等功能。聊天界面如下图所示:下面将按步骤介绍该系统的设计实现,首先在linu…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
如何在最短时间内提升打ctf(web)的水平?
刚刚刷完2遍 bugku 的 web 题,前来答题。 每个人对刷题理解是不同,有的人是看了writeup就等于刷了,有的人是收藏了writeup就等于刷了,有的人是跟着writeup做了一遍就等于刷了,还有的人是独立思考做了一遍就等于刷了。…...
【Go语言基础【12】】指针:声明、取地址、解引用
文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
