WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。

WebSocket通信协议于2011年被IETF定为标准RFC 6455,并被RFC7936所补充规范。

在golang语言中,目前有两种比较常用的实现方式:一个是golang自带的库,另一个是gorilla,功能强大。

golang自带库的使用例子可参考以前的博文:Golang如何使用websocket

本文以gorilla为例,介绍websocket的使用。

下载gorilla

# go get github.com/gorilla/websocket

下面例子中主要包括两部分,server和client。

client部分又包括:web client(浏览器)和非web client。

server

server端是一个HTTP 服务器,监听8080端口。

当接收到连接请求后,将连接使用的http协议升级为websocket协议。后续通信过程中,使用websocket进行通信。

对每个连接,server端等待读取数据,读到数据后,打印数据,然后,将数据又发送给client.

server启动方式

# go run server.go

server.go代码如下:

// Copyright 2015 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // +build ignore package main import (
"flag"
"html/template"
"log"
"net/http" "github.com/gorilla/websocket"
) var addr = flag.String("addr", "localhost:8080", "http service address") var upgrader = websocket.Upgrader{} // use default options func echo(w http.ResponseWriter, r *http.Request) {
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("upgrade:", err)
return
}
defer c.Close()
for {
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
log.Printf("recv: %s", message)
err = c.WriteMessage(mt, message)
if err != nil {
log.Println("write:", err)
break
}
}
} func home(w http.ResponseWriter, r *http.Request) {
homeTemplate.Execute(w, "ws://"+r.Host+"/echo")
} func main() {
flag.Parse()
log.SetFlags(0)
http.HandleFunc("/echo", echo)
http.HandleFunc("/", home)
log.Fatal(http.ListenAndServe(*addr, nil))
} var homeTemplate = template.Must(template.New("").Parse(`
<!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.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>
<p><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>
`))

server output:

recv: 2018-10-20 17:09:12.497129965 +0800 CST m=+1.010137585

recv: 2018-10-20 17:09:13.495602484 +0800 CST m=+2.008641088

recv: 2018-10-20 17:09:14.49401062 +0800 CST m=+3.007080206

recv: 2018-10-20 17:09:15.497114615 +0800 CST m=+4.010215329

recv: 2018-10-20 17:09:16.494394706 +0800 CST m=+5.007526368

read: websocket: close 1000 (normal)

非web client

client启动后,首先连接server。

连接建立后,主routine每一秒钟向server发送消息(当前时间)。

另一个routine从server接收数据,并打印。

当client退出时,会向server发送关闭消息。接着,等待退出。

client启动方式

# go run client.go

client代码如下:

// Copyright 2015 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // +build ignore package main import (
"flag"
"log"
"net/url"
"os"
"os/signal"
"time" "github.com/gorilla/websocket"
) var addr = flag.String("addr", "localhost:8080", "http service address") func main() {
flag.Parse()
log.SetFlags(0) interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt) u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo"}
log.Printf("connecting to %s", u.String()) c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
log.Fatal("dial:", err)
}
defer c.Close() done := make(chan struct{}) go func() {
defer close(done)
for {
_, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
return
}
log.Printf("recv: %s", message)
}
}() ticker := time.NewTicker(time.Second)
defer ticker.Stop() for {
select {
case <-done:
return
case t := <-ticker.C:
err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
if err != nil {
log.Println("write:", err)
return
}
case <-interrupt:
log.Println("interrupt") // Cleanly close the connection by sending a close message and then
// waiting (with timeout) for the server to close the connection.
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println("write close:", err)
return
}
select {
case <-done:
case <-time.After(time.Second):
}
return
}
}
}

client output:

connecting to ws://localhost:8080/echo

recv: 2018-10-20 17:09:12.497129965 +0800 CST m=+1.010137585

recv: 2018-10-20 17:09:13.495602484 +0800 CST m=+2.008641088

recv: 2018-10-20 17:09:14.49401062 +0800 CST m=+3.007080206

recv: 2018-10-20 17:09:15.497114615 +0800 CST m=+4.010215329

recv: 2018-10-20 17:09:16.494394706 +0800 CST m=+5.007526368

^Cinterrupt

read: websocket: close 1000 (normal)

web client

web client,也就是使用浏览器。

在浏览器中输入http://127.0.0.1:8080

"Open",然后"send"

server output:

recv: Hello world!!

参考

百度百科

https://baike.baidu.com/item/WebSocket

github

https://github.com/gorilla/websocket

doc

https://godoc.org/github.com/gorilla/websocket

example

https://github.com/gorilla/websocket/blob/master/examples/

golang gorilla websocket例子的更多相关文章

  1. golang实现WebSocket的商业化使用的开发逻辑(1)

    WebSocket是什么 WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议.其最大特点之一就是:服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对 ...

  2. golang之websocket 源码分析

    下载go的websocket包. 1. 通过google官方的方法, 需要hg来同步代码. 由于墙的原因, 还需要设置代理. 比较麻烦 2. http://gopm.io/ 通过该网站下载, 这是go ...

  3. 带ssl的websocket例子

    还是在那个websocket_demo的例子 rebar-creator create-app websocket_demo tree一下看看大概目录 ├── cert │   ├── cowboy- ...

  4. golang 移动应用例子 example/basic 源码框架分析

    条件编译 我们在源码中可以看到2个文件: main.go 和 main_x.go 这两个包名都是 package main , 都有 main 函数. 不会冲突么? 答案是不会的, main_x.go ...

  5. (网页)websocket例子

    转载自博客园张果package action; import javax.websocket.CloseReason; import javax.websocket.OnClose; import j ...

  6. 基于netty的websocket例子

    nettyServer package com.atguigu.netty.websocket; import javax.annotation.PostConstruct; import org.s ...

  7. erlang的websocket例子

    创建工程 rebar-creator create-app websocket_demo 文件列表 route_helper.erl -module(route_helper). -export([g ...

  8. Springboot WebSocket例子

    Springboot整合WebSocket 1.application.properties #设置服务端口号 server.port=8080 #thymeleaf配置 #是否启用模板缓存. spr ...

  9. golang LMDB入门例子——key range查询

    如下,使用gomb库 package main import ( "bytes" "fmt" "io/ioutil" "os&qu ...

随机推荐

  1. java学习笔记12(final ,static修饰符)

    final: 意思是最终的,是一个修饰符,有时候一个功能类被开发好了,不想被子类重写就用final定义, 用final修饰的最终数据成员:如果一个类的数据成员用final修饰符修饰,则这个数据成员就被 ...

  2. 最新2018年三月可用Windows10激活密钥

    Windows 10 Edition Product Key Windows 10 Home TX9XD-98N7V-6WMQ6-BX7FG-H8Q99 Windows 10 Home Single ...

  3. 路由器DHCP服务及DHCP中继

    实验要求:掌握路由配置DHCP服务配置 拓扑如下: R1enable 进入特权模式config terminal   进入全局模式interface s0/0/0 进入端口ip address 192 ...

  4. 何时使用SUM()与SUMX()

    概述 SUM()是一个聚合函数.在应用将影响公式的所有过滤器后,它会将您指定的单个列中的所有值相加.SUM()不知道行的存在(它不能逐行求值) - 它所能做的就是在应用过滤器之后将所有内容添加到它所呈 ...

  5. lvm创建和快照

    查看磁盘 创建分区 新建1G的1分区 新建1G的2分区 新建1G的3分区 查看新建的分区 因标准分区是83交换分区是82做lv是8e所以要改变类型 查看: 保存退出: 创建物理卷pv 将物理卷pv创建 ...

  6. Linux sort命令详解

    linux之sort用法 sort命令是帮我们依据不同的数据类型进行排序,其语法及常用参数格式: sort [-bcfMnrtk][源文件][-o 输出文件] 补充说明:sort可针对文本文件的内容, ...

  7. opencv的DMatch

    1.DMatch是描述图像匹配信息的类 /** @brief Class for matching keypoint descriptors query descriptor index, train ...

  8. POJ 2751:Seek the Name, Seek the Fame(Hash)

    Seek the Name, Seek the Fame Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 24077   Ac ...

  9. 第8次Scrum会议(10/20)【欢迎来怼】

    一.小组信息 队名:欢迎来怼 小组成员 队长:田继平 成员:李圆圆,葛美义,王伟东,姜珊,邵朔,冉华 小组照片 二.开会信息 时间:2017/10/20 17:20~17:45,总计25min. 地点 ...

  10. get android or ios appname

    get app name from GP or itunes var superagent = require('superagent'); var cheerio = require('cheeri ...