Go语言【项目】 websocket消息服务
websocket消息服务
目的:搭建websocket服务,用浏览器与服务进行消息交互(写的第一个Go程序)
代码目录结构:
前端html页面:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
window.addEventListener("load", function(evt) {
var output = document.getElementById("output");
var input = document.getElementById("input");
var ws;
var print = function(message) {
var d = document.createElement("div");
d.innerHTML = message;
output.appendChild(d);
};
document.getElementById("open").onclick = function(evt) {
if (ws) {
return false;
}
ws = new WebSocket("ws://127.0.0.1:7777/ws");
ws.onopen = function(evt) {
print("OPEN");
}
ws.onclose = function(evt) {
print("CLOSE");
ws = null;
}
ws.onmessage = function(evt) {
print("RESPONSE: " + evt.data);
}
ws.onerror = function(evt) {
print("ERROR: " + evt.data);
}
return false;
};
document.getElementById("send").onclick = function(evt) {
if (!ws) {
return false;
}
print("SEND: " + input.value);
ws.send(input.value);
return false;
};
document.getElementById("close").onclick = function(evt) {
if (!ws) {
return false;
}
ws.close();
return false;
};
});
</script>
</head>
<body>
<table>
<tr><td valign="top" width="50%">
<p>Click "Open" to create a connection to the server,
"Send" to send a message to the server and "Close" to close the connection.
You can change the message and send multiple times.
</p>
<form>
<button id="open">Open</button>
<button id="close">Close</button>
<input id="input" type="text" value="Hello world!">
<button id="send">Send</button>
</form>
</td><td valign="top" width="50%">
<div id="output"></div>
</td></tr></table>
</body>
</html>
client.html
server.go代码:
package main import (
"fmt"
"github.com/gorilla/websocket"
"go_websocket"
"net/http"
) // http升级websocket协议的配置
var wsUpgrader = websocket.Upgrader{
// 允许跨域CORS
CheckOrigin: func(r *http.Request) bool {
return true
},
} // 消息处理
func wsHandler(resp http.ResponseWriter, req *http.Request) {
wsSocket, err := wsUpgrader.Upgrade(resp, req, nil)
if err != nil {
return
}
wsConn := go_websocket.WsConnectionInit(wsSocket)
wsConn.Run() for {
wsmsg, err := wsConn.ReadMessage()
if err != nil {
goto error
}
err = wsConn.WriteMessage(wsmsg)
if err != nil {
goto error
}
}
error:
fmt.Println("websocket is closed")
return
} func main() {
fmt.Println("websocket start")
http.HandleFunc("/ws", wsHandler)
http.ListenAndServe("0.0.0.0:7777", nil)
}
connection.go代码:
package go_websocket import (
"errors"
"fmt"
"github.com/gorilla/websocket"
"sync"
"time"
) // 客户端读写消息
type WsMessage struct {
msgType int
data []byte
} // 客户端连接
type wsConnection struct {
wsSocket *websocket.Conn
inChan chan *WsMessage
outChan chan *WsMessage isClosed bool
closeChan chan []byte
mutex sync.Mutex
} // 连接初始化
func WsConnectionInit(wsSocket *websocket.Conn) (wsConn *wsConnection) {
wsConn = &wsConnection{
wsSocket: wsSocket,
inChan: make(chan *WsMessage, 1000),
outChan: make(chan *WsMessage, 1000),
closeChan: make(chan []byte, 1),
}
return wsConn
} // 启动
func (wsConn *wsConnection) Run() {
go wsConn.readLoop()
go wsConn.writeLoop()
go wsConn.heartbeat()
} // 心跳检测
func (wsConn *wsConnection) heartbeat() {
for {
time.Sleep(2 * time.Second)
wsmsg := &WsMessage{msgType: websocket.TextMessage, data: []byte("heartbeat")}
err := wsConn.WriteMessage(wsmsg)
if err != nil {
fmt.Println("send heartbeat stop")
return
}
}
} // 循环接收
func (wsConn *wsConnection) readLoop() {
var () for {
msgType, data, err := wsConn.wsSocket.ReadMessage()
if err != nil {
goto error
}
select {
case wsConn.inChan <- &WsMessage{msgType: msgType, data: data}:
case <-wsConn.closeChan:
goto closed
}
}
error:
wsConn.Close()
closed:
fmt.Println("readLoop closed")
} // 循环发送
func (wsConn *wsConnection) writeLoop() {
for {
select {
case wsmsg := <-wsConn.outChan:
if err := wsConn.wsSocket.WriteMessage(wsmsg.msgType, wsmsg.data); err != nil {
goto error
}
case <-wsConn.closeChan:
goto closed
}
}
error:
wsConn.Close()
closed:
fmt.Println("writeLoop close")
} // 取消息,外部可调用
func (wsConn *wsConnection) ReadMessage() (wsmsg *WsMessage, err error) {
select {
case wsmsg = <-wsConn.inChan:
return wsmsg, nil
case <-wsConn.closeChan:
return nil, errors.New("websocket is closed")
}
} // 写消息,外部可调用
func (wsConn *wsConnection) WriteMessage(wsmsg *WsMessage) (err error) {
select {
case wsConn.outChan <- wsmsg:
case <-wsConn.closeChan:
return errors.New("websocket is closed")
}
return nil
} // 关闭wsSocket
func (wsConn *wsConnection) Close() {
wsConn.wsSocket.Close() // 加锁
wsConn.mutex.Lock()
if !wsConn.isClosed {
wsConn.isClosed = true
close(wsConn.closeChan)
}
wsConn.mutex.Unlock()
}
效果展示:
Go语言【项目】 websocket消息服务的更多相关文章
- 基于Go的websocket消息服务
3个月没写PHP了,这是我的第一个中小型go的websocket微服务.那么问题来了,github上那么多轮子,我为什么要自己造轮子呢? Why 造轮子? 因为这样不仅能锻炼自己的技术能力,而且能帮助 ...
- Centrifugo 语言无关的实时消息服务
Centrifugo 语言无关的实时消息服务,基于golang编写,提供了websocket 以及sockjs 的兼容处理,使用上很简单 同时也支持基于redis的扩展,以下是一个简单的运行测试 环境 ...
- 搭建websocket消息推送服务,必须要考虑的几个问题
近年,不论是正在快速增长的直播,远程教育以及IM聊天场景,还是在常规企业级系统中用到的系统提醒,对websocket的需求越来越大,对websocket的要求也越来越高.从早期对websocket的应 ...
- Spring Boot 集成 WebSocket 实现服务端推送消息到客户端
假设有这样一个场景:服务端的资源经常在更新,客户端需要尽量及时地了解到这些更新发生后展示给用户,如果是 HTTP 1.1,通常会开启 ajax 请求询问服务端是否有更新,通过定时器反复轮询服务端响应的 ...
- JMS(java消息服务)整合Spring项目案例
转载自云栖社区 摘要: Sprng-jms消息服务小项目 所需的包: spring的基础包 spring-jms-xx包 spring-message–xx包 commons-collection-x ...
- 模拟websocket推送消息服务mock工具二
模拟websocket推送消息服务mock工具二 在上一篇博文中有提到<使用electron开发一个h5的客户端应用创建http服务模拟后端接口mock>使用electron创建一个模拟后 ...
- spring集成webSocket实现服务端向前端推送消息
原文:https://blog.csdn.net/ya_nuo/article/details/79612158 spring集成webSocket实现服务端向前端推送消息 1.前端连接webso ...
- “一切都是消息”--MSF(消息服务框架)入门简介
“一切都是消息”--这是MSF(消息服务框架)的设计哲学. MSF的名字是 Message Service Framework 的简称,中文名称:消息服务框架,它是PDF.NET框架的一部分. 1,M ...
- “一切都是消息”--iMSF(即时消息服务框架)入门简介
“一切都是消息”--这是iMSF(即时消息服务框架)的设计哲学. MSF的名字是 Message Service Framework 的简称,由于目前框架主要功能在于处理即时(immediately) ...
随机推荐
- 网站怎么上传到服务器流程,从本地到服务器上线过程并通过域名(IP地址)进行访问
制作好的网页想要发布到互联网,该怎么发布呢?我们需要将保存在本地的站点上传站点到服务器,首先我们需要准备一个服务器(可通过服务器公网IP地址访问),也可以购买域名,域名购买可以通过阿里云.腾讯云.百度 ...
- idea 忽略提交文件
https://blog.csdn.net/wangjun5159/article/details/74932433 https://blog.csdn.net/m0_38001814/article ...
- OGG 源端与目标端 约束不一致
需求: 请在生产库执行下面的脚本 --删除主键并新增复合主键 alter table XXXXX drop constraint PK_USERCHNL cascade; ...
- Windows实时预览markdown
1.安装Notepad++ 2.打开Notepad++菜单栏的"插件(P)",然后打开"插件管理" 3.搜索"MarkdownViewer++&quo ...
- rhel7 学习第三天
<Linux就该这么学>学习第三天,掌握了一些常用的命令
- KL散度=交叉熵-熵
熵:可以表示一个事件A的自信息量,也就是A包含多少信息. KL散度:可以用来表示从事件A的角度来看,事件B有多大不同. 交叉熵:可以用来表示从事件A的角度来看,如何描述事件B. 一种信息论的解释是: ...
- Winform 弹框增加确定按钮并点击确定后进行下一步操作
//审核完毕后调用打印 MessageBoxButtons messButton = MessageBoxButtons.OKCancel; DialogResult dr = MsgBox.Show ...
- MapReduce 程序mysql JDBC驱动类找不到原因及学习hadoop写入数据到Mysql数据库的方法
报错 :ClassNotFoundException: com.mysql.jdbc.Driver 需求描述: hadoop需要动态加载个三方jar包(比如mysql JDBC 驱动包),是在MR结束 ...
- 阿里云centos 7上面安装mysql5.7的详细步骤!!!
前言: 网上太多的linux 的安装mysql教程,很多教程不全或者因为环境不一致导致无法成功安装,以下是亲测的可行性的方法,请参考. 步骤: Centos7操作系统YUM库列表里默认不再提供MySQ ...
- SPA项目开发之登录注册
CMD安装所需要的pom依赖 npm install element-ui -S npm install axios -S npm install qs -S npm install vue-axio ...