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消息服务的更多相关文章

  1. 基于Go的websocket消息服务

    3个月没写PHP了,这是我的第一个中小型go的websocket微服务.那么问题来了,github上那么多轮子,我为什么要自己造轮子呢? Why 造轮子? 因为这样不仅能锻炼自己的技术能力,而且能帮助 ...

  2. Centrifugo  语言无关的实时消息服务

    Centrifugo 语言无关的实时消息服务,基于golang编写,提供了websocket 以及sockjs 的兼容处理,使用上很简单 同时也支持基于redis的扩展,以下是一个简单的运行测试 环境 ...

  3. 搭建websocket消息推送服务,必须要考虑的几个问题

    近年,不论是正在快速增长的直播,远程教育以及IM聊天场景,还是在常规企业级系统中用到的系统提醒,对websocket的需求越来越大,对websocket的要求也越来越高.从早期对websocket的应 ...

  4. Spring Boot 集成 WebSocket 实现服务端推送消息到客户端

    假设有这样一个场景:服务端的资源经常在更新,客户端需要尽量及时地了解到这些更新发生后展示给用户,如果是 HTTP 1.1,通常会开启 ajax 请求询问服务端是否有更新,通过定时器反复轮询服务端响应的 ...

  5. JMS(java消息服务)整合Spring项目案例

    转载自云栖社区 摘要: Sprng-jms消息服务小项目 所需的包: spring的基础包 spring-jms-xx包 spring-message–xx包 commons-collection-x ...

  6. 模拟websocket推送消息服务mock工具二

    模拟websocket推送消息服务mock工具二 在上一篇博文中有提到<使用electron开发一个h5的客户端应用创建http服务模拟后端接口mock>使用electron创建一个模拟后 ...

  7. spring集成webSocket实现服务端向前端推送消息

    原文:https://blog.csdn.net/ya_nuo/article/details/79612158 spring集成webSocket实现服务端向前端推送消息   1.前端连接webso ...

  8. “一切都是消息”--MSF(消息服务框架)入门简介

    “一切都是消息”--这是MSF(消息服务框架)的设计哲学. MSF的名字是 Message Service Framework 的简称,中文名称:消息服务框架,它是PDF.NET框架的一部分. 1,M ...

  9. “一切都是消息”--iMSF(即时消息服务框架)入门简介

    “一切都是消息”--这是iMSF(即时消息服务框架)的设计哲学. MSF的名字是 Message Service Framework 的简称,由于目前框架主要功能在于处理即时(immediately) ...

随机推荐

  1. webpack报错

    webpack-dev-server --inline --progress --config build/webpack.dev.conf.js internal/modules/cjs/loade ...

  2. Vue 动态控制页面中按钮是否显示和样式

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. vue展示md文件,前端读取展示markdown文件

    方案1:每次都需要重新打包,每次修改都需要build 直接使用require + v-html: 核心代码如下: 1. 首先需要添加MD文件的loader就是 markdown-loader npm ...

  4. Keepalived与MySQL互为主从自动切换配置

    为解决Mysql数据库单点问题,实现两台MySQL数据库互为主备,双向replication.当一Master出现问题,则将Slave切换为Master继续工作. 环境说明 系统版本:CentOS L ...

  5. 爬取 豆瓣电影Top250

    目标 学习爬虫,爬豆瓣榜单,获取爬取静态页面信息的能力 豆瓣电影 Top 250  https://movie.douban.com/top250 代码 import requests from bs ...

  6. uwsgi no python application found错误的解决(python3+centos6)

    近期在努力把自己的项目从python2转到python3上,因为生产环境无法抛弃centos7,所以只好在centos7上安装了python3.装好了python3,将python命令软连接改成pyt ...

  7. Centos7添加磁盘并分区格式化

    1.安装前准备 [root@localhost ~]# yum install xfsprogs [root@localhost ~]# modprobe xfs [root@localhost ~] ...

  8. Ubuntu 开发环境搭建教程

    Ubuntu 开发环境搭建教程 本文原始地址:https://sitoi.cn/posts/18425.html 更新 sudo apt upgrade sudo apt update 生成本机密钥 ...

  9. 深浅拷贝、集合set、函数、日志

    #-----深浅拷贝---- import copy a = ["xiaoming",111,[5000,2000]] b = a print("b:%s" % ...

  10. tf.Variable()、tf.get_variable()和tf.placeholder()

    1.tf.Variable() tf.Variable(initializer,name) 功能:tf.Variable()创建变量时,name属性值允许重复,检查到相同名字的变量时,由自动别名机制创 ...