当前位置: 首页 > news >正文

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>![在这里插入图片描述](https://img-blog.csdnimg.cn/64552642dadb45a18bcfc34020cfff40.png)
多开几个网页就可以呀聊天

相关文章:

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 是微软公司推出的一款设计工具&#xff0c;主要用于快速创建Web和移动应用程序的原型设计。它提供了一系列的工具和模板&#xff0c;可以帮助用户…...

《Docker系列》Docker容器修改配置文件后,重启失败,如何修改配置并启动容器?

Docker容器修改配置文件后&#xff0c;重启失败&#xff0c;如何修改配置并启动容器&#xff1f; docker部署的MySQL容器&#xff0c;修改了my.cnf配置文件&#xff0c;重启的时候导致无法启动 通过查日志发现&#xff0c;配置文件中的binlog-db-dbhw写错了&#xff0c;应该是…...

遇到多个构造器参数时要考虑使用构建器

静态工厂和构造器有个共同的局限性&#xff1a;他们都不能很好地扩展到大量的可选参数。比如用一个类表示包装食品外面显示的营养成分标签&#xff08;包括必选域和可选域&#xff09;。 重叠构造器 对于这样的类一般习惯采用重叠构造器&#xff08;telescoping constructor&…...

【Storm】【五】Storm集成Kafka

Storm集成Kafka 一、整合说明二、写入数据到Kafka三、从Kafka中读取数据一、整合说明 Storm 官方对 Kafka 的整合分为两个版本&#xff0c;官方说明文档分别如下&#xff1a; Storm Kafka Integration : 主要是针对 0.8.x 版本的 Kafka 提供整合支持&#xff1b;Storm Kafka …...

GVRP-LNP-VCMP讲解

目录 GVRP讲解 动态创建Vlan并将端口加入Vlan GVRP消息类型 GVRP工作原理 LNP讲解 动态修改接口链路类型 VCMP讲解 动态创建Vlan 相关概念 Vlan同步 VCMP与GVRP的区别 GVRP讲解 动态创建Vlan并将端口加入Vlan GVRP&#xff08;GARR Vlan Registration Protocol&#xf…...

28个精品Python爬虫实战项目

先来说说Python的优势&#xff01;然后给大家看下这28个实战项目的实用性&#xff01;Python跟其他语言相比&#xff0c;有以下优点&#xff1a;1. 简单Python是所有编程语言里面&#xff0c;代码量最低&#xff0c;非常易于读写&#xff0c;遇到问题时&#xff0c;程序员可以把…...

相信人还是相信ChatGPT,龙测首席AI专家给出了意料之外的答案

最近&#xff0c;关于ChatGPT的话题太火了&#xff01;各大社交软件都是他的消息&#xff01;从去年12月份ChatGPT横空出世&#xff0c;再到近期百度文心一言、复旦Moss的陆续宣布&#xff0c;点燃了全球对AIGC&#xff08;内容人工智能自动生成&#xff09;领域的热情&#xf…...

安卓逆向_5 --- jeb 和 AndroidStudio 动态调试 smali

Jeb 工具的使用 &#xff1a;https://www.52pojie.cn/forum.php?modviewthread&tid742250&#xff1a;https://zhuanlan.zhihu.com/p/302856081动态调试 smali 有两种方法&#xff1a; Jeb 调试AndroidStudio smalidea 插件动态调试。1、Jeb 动态调试 smali ​JEB是一个…...

docker-容器命令

1.新建启动 docker run options image command [arg..] options: --name"容器新名字" -d&#xff1a;后台运行程序 -it&#xff1a;交互式运行 -P: 随机端口 -p: 指定端口 docker run -it ubuntu /bin/bash docker run -it ubuntu:v1 /bin/bash docker run -it 1c352…...

Spring——是什么?作用?内容?用到的设计模式?

目录 什么是spring&#xff1f; spring是为了解决什么问题而衍生的&#xff1f;&#xff08;历史&#xff09;Spring解决了实际生产中的什么问题&#xff1f; spring包含了哪些部分&#xff1f;&#xff08;组成&#xff09; Spring的特点是什么&#xff1f; spring框架中…...

Qt交叉编译环境搭建

环境及版本&#xff1a; 编译机&#xff1a;Deepin 20.3 Qt 5.12.9 arm编译工具&#xff1a; gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-gnueabihf.tar.xz 运行机&#xff1a;创龙335X开发板 1.下载arm编译工具&#xff1a; gcc-linaro-6.5.0-2018.12-x86_64_arm-linux-…...

Java switch case 语句

Java 的 switch case 语句是一种常用的控制流语句&#xff0c;用于基于不同的输入值执行不同的操作。本文将详细介绍 Java switch case 语句的作用、用法以及在实际工作中的应用。 一、switch case 语句的作用 switch case 语句是一种多分支条件语句&#xff0c;它基于不同的输…...

Linux下MQTT客户端消息订阅与发布实现

MQTT(消息队列遥测传输)是一个基于客户端-服务器的消息发布/订阅传输协议。它基于TCP协议&#xff0c;默认端口号为1883&#xff0c;为此&#xff0c;它也需要一个消息中间件 。MQTT协议是轻量、简单、开放和易于实现的&#xff0c;这些特点使它适用范围非常广泛。在很多情况下…...

代码规范----编程规约(下)

目录 四、OOP规约 五、日期时间 六、集合处理 四、OOP规约 &#xff08;1&#xff09;、避免通过一个类的对象引用访问此类的静态变量或静态方法&#xff0c;无谓增加编译器解析成本&#xff0c;直接用类名来访问即可 &#xff08;2&#xff09;、所有的覆写方法&#xff0…...

c++连接mysql

开始想用mysql connector/c8.0 来操作数据库cmake加上配置后一直编译错误 我这里也没有截屏编译错误大概意思是driver.h里面声明的一个check_lib函数里面用了一个未定义的check找遍了资料都没有找到解决办法最后还是用了原始API如果有人有解决办法请留个位置先上在用的cmake配置…...

CentOS7操作系统安装nginx实战(多种方法,超详细)

文章目录前言一. 实验环境二. 使用yum安装nginx2.1 添加yum源2.1.1 使用官网提供的源地址&#xff08;方法一&#xff09;2.1.2 使用epel的方式进行安装&#xff08;方法二&#xff09;2.2 开始安装nginx2.3 启动并进行测试2.4 其他的一些用法&#xff1a;三. 编译方式安装ngin…...

【测绘程序设计】——空间直角坐标转换

测绘工程中经常遇到空间直角坐标转换——比如,北京54(或西安80)空间直角坐标转换成CGCS2000(或WGS-84)空间直角坐标,常用转换模型包括:①布尔沙模型(国家级及省级范围);②莫洛坚斯基模型(省级以下范围);③三维四参数(小于22局部区域) 等。   本文分享了基于布…...

数组--java--动态数组--有序数组--底层

java数组基础--java中的数组创建数组空间占用初始化数组访问元素插入查找删除元素动态数组扩容插入和添加重写toString删除二维数组二维数组注意点有序数组实现测试写在开头&#xff1a; 这篇文章包括数组的基础、一点底层的内容和一些稍微深入的东西。 作为第一个深入学习的数…...

Linux下使用C语言实现简单的聊天室程序

本文章介绍一种基于Linux使用C语言实现简单的局域网聊天室程序的方法&#xff0c;支持消息群发&#xff0c;历史数据查询&#xff0c;好友列表查看&#xff0c;好友上线下线提醒等功能。聊天界面如下图所示&#xff1a;下面将按步骤介绍该系统的设计实现&#xff0c;首先在linu…...

【数学】任意一个正整数n最多只有一个质因数大于根号n,怎么证明?

定理 任意一个正整数n最多只有一个大于n\sqrt{n}n​的质因子&#xff0c;并且该大于n\sqrt{n}n​质因子的幂次是1。 证明&#xff08;反证法&#xff09; 证明&#xff1a;最多只有一个大于n\sqrt{n}n​的质因子 假设n存在两个大于n\sqrt{n}n​的质因子&#xff0c;分别为p…...

【ES6】var let const 之面试题系列

关于 var、let、const 是前端开发人员经常用到的关键字&#xff0c;也是经典的面试题&#xff0c;接下来就站在面试题的角度来看待它们之间的区别。 一、区别 1. var 声明的范围是函数作用域&#xff0c;let 和 const 声明的范围是块作用域&#xff0c;块作用域是函数作用域的…...

Vue基础入门讲义(四)-组件化

文章目录1.引言2.定义全局组件3.组件的复用4.局部注册5.组件通信5.1.父向子传递props5.2.传递复杂数据5.3.子向父的通信1.引言 在大型应用开发的时候&#xff0c;页面可以划分成很多部分。往往不同的页面&#xff0c;也会有相同的部分。例如可能会有相同的头部导航。 但是如果…...

Android onLayout布局流程解析

组件布局流程结论 1.&#xff09;layout流程始于ViewRootImpl的performLayout()方法&#xff0c;该方法会调用根View&#xff08;DecorView&#xff09;的layout()方法进行布局&#xff0c;因为DecorView是ViewGroup(FrameLayout),所以layout流程来到了ViewGroup&#xff08;其…...

浅分析BIG-建筑展示系统

一、主页&#xff08;主要界面&#xff09;重点疑点&#xff08;需要解决&#xff09;1.云平台实时同步。是否可以电脑与hololens2同步或链接&#xff1f;并可以传输信息提醒&#xff1f;一级界面&#xff08;启动界面&#xff09;1.交互式启动激活效果&#xff08;触发按钮旋转…...

模电基础(1) 半导体基础知识

基本内容&#xff1a; 1.本征半导体的基本介绍结构&#xff1b; 2.杂质半导体&#xff1b; 3.PN结的形成&#xff1b; 4.PN结的性质。 1.本征半导体 半导体&#xff1a;导电性能介于绝缘体和导体之间的物质。 本征半导体是纯净的晶体结构的半导体。 纯净→无杂质晶体结构→稳…...

阅读笔记:TF - IDF 原理

今天查阅 TF-IDF 资料&#xff0c;发现百度百科里面提供了一个例子&#xff0c;解释的很清楚&#xff0c;记下来备用。 原文链接&#xff1a;https://baike.baidu.com/item/tf-idf/8816134?fraladdin 例子&#xff1a;在某个一共有一千词的网页中 “原子能”、“的” 和 “应…...

【C语言】float 关键字

&#x1f6a9;write in front&#x1f6a9; &#x1f50e;大家好&#xff0c;我是謓泽&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f3c5;2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4…...

Linux 网络编程(实现多路IO转接服务器)

1.select函数实现多路IO转接服务器select函数原型&#xff1a;包含在头文件<sys/time.h>&#xff0c;<sys/types.h>和<unistd.h>int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);作用&#xff1a;确定…...

DC-4 靶场学习

信息搜集&#xff1a; 首先获取靶场ip&#xff0c;和之前一样。 arp-scan -l nmap -sP 192.168.28.0/24然后访问。 发现需要登录。 漏洞分析: 直接用bp爆破&#xff0c;爆破出来密码为happy&#xff0c;登录。 发现执行了命令&#xff0c;抓包。 修改命令可以执行&#xff…...