如果只是想了解chat的实现方式,在gorilla和revel框架里面都有完整的chat实例可以提供参考。本篇讲解的是,如何基于martini实现websocket的聊天。

配置步骤:

1 已经安装了go命令,配置了GOPATH

2 安装gorilla/websocket

go get github.com/gorilla/websocket

3 安装martini

go get github.com/go-martini/martini

项目文件列表

$GOPATH/demo/home.html
$GOPATH/demo/martini_ws.go

home.html 代码

<!DOCTYPE html>
<html lang="en">
<head>
<title>Chat Example</title>
<script type="text/javascript">
window.onload = function () {
var conn;
var msg = document.getElementById("msg");
var log = document.getElementById("log"); function appendLog(item) {
var doScroll = log.scrollTop === log.scrollHeight - log.clientHeight;
log.appendChild(item);
if (doScroll) {
log.scrollTop = log.scrollHeight - log.clientHeight;
}
} document.getElementById("form").onsubmit = function () {
if (!conn) {
return false;
}
if (!msg.value) {
return false;
}
conn.send(msg.value);
msg.value = "";
return false;
}; if (window["WebSocket"]) {
conn = new WebSocket("ws://{{$}}/ws");
conn.onclose = function (evt) {
var item = document.createElement("div");
item.innerHTML = "<b>Connection closed.</b>";
appendLog(item);
};
conn.onmessage = function (evt) {
var messages = evt.data.split('\n');
for (var i = ; i < messages.length; i++) {
var item = document.createElement("div");
item.innerText = messages[i];
appendLog(item);
}
};
} else {
var item = document.createElement("div");
item.innerHTML = "<b>Your browser does not support WebSockets.</b>";
appendLog(item);
}
};
</script>
<style type="text/css">
html {
overflow: hidden;
} body {
overflow: hidden;
padding: ;
margin: ;
width: %;
height: %;
background: gray;
} #log {
background: white;
margin: ;
padding: .5em .5em .5em .5em;
position: absolute;
top: .5em;
left: .5em;
right: .5em;
bottom: 3em;
overflow: auto;
} #form {
padding: .5em .5em;
margin: ;
position: absolute;
bottom: 1em;
left: 0px;
width: %;
overflow: hidden;
} </style>
</head>
<body>
<div id="log"></div>
<form id="form">
<input type="submit" value="Send" />
<input type="text" id="msg" size=""/>
</form>
</body>
</html>

martini_ws.go代码

package main

import (
"fmt"
"github.com/go-martini/martini"
"github.com/gorilla/websocket"
"log"
"net/http"
"text/template"
) const (
readBufferSize =
writeBufferSize =
) type Client struct {
conn *websocket.Conn
messages chan []byte
} var clients map[*Client]bool // 存储所有的链接
var broadcast chan []byte // 广播聊天的chan
var addClients chan *Client // 新链接进来的chan func (c *Client) readPump() {
for {
_, message, err := c.conn.ReadMessage()
if err != nil {
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
log.Printf("error: %v", err)
}
break
}
fmt.Printf("receive message is :%s\n", message)
broadcast <- message
}
} func (c *Client) writePump() {
for {
select {
case message := <-c.messages:
fmt.Printf("send message is :%s\n", message)
c.conn.WriteMessage(, message)
}
}
} func manager() { clients = make(map[*Client]bool)
broadcast = make(chan []byte, )
addClients = make(chan *Client) for {
select {
case message := <-broadcast:
for client := range clients {
select {
case client.messages <- message:
default:
close(client.messages)
delete(clients, client)
}
}
case itemClient := <-addClients:
clients[itemClient] = true
}
}
} func main() { var homeTemplate = template.Must(template.ParseFiles("home.html")) m := martini.Classic() m.Get("/", func(res http.ResponseWriter, req *http.Request) { res.Header().Set("Content-Type", "text/html; charset=utf-8")
homeTemplate.Execute(res, req.Host)
}) m.Get("/ws", func(res http.ResponseWriter, req *http.Request) { // res and req are injected by Martini
conn, err := websocket.Upgrade(res, req, nil, readBufferSize, writeBufferSize)
if err != nil {
log.Println(err)
return
}
client := &Client{conn: conn, messages: make(chan []byte, )}
addClients <- client
go client.writePump()
client.readPump()
}) go manager() m.RunOnAddr(":3010")
//m.Run() }

按照上面的步骤建好文件,就可以运行了。m.RunOnAddr 可以改成你需要的端口

执行命令:

go run martini_ws.go

在浏览器输入 http://localhost:3010 就能访问你本机的聊天服务了

参考地址

https://github.com/patcito/martini-gorilla-websocket-chat-example

  

go语言从零学起(四) -- 基于martini和gorilla实现的websocket聊天实例的更多相关文章

  1. go语言从零学起(三) -- chat实现的思考

    要通过go实现一个应用场景: 1 建立一个websocket服务 2 维护在线用户的链接 3 推送消息和接受用户的操作 列出需求,很显然的想到了chat模型.于是研究了revel框架提供的sample ...

  2. go语言从零学起(一) -- 文档教程篇

    先记录一下自己学go语言的出发点 作为一个phper,精通一门底层语言一直是努力的目标. 相对于c,c++,go语言不需要过多的关注指针,内存释放,一两行代码就能跑起一个server服务,简直不要太简 ...

  3. go语言从零学起(二)--list循环删除元素(转载)

    本篇系转载 在使用go的container/list的package时,你可能会无意间踩一个小坑,那就是list的循环删除元素. list删除元素,直观写下来的代码如下: package main i ...

  4. 从零学脚手架(四)---babel

    如果此篇对您有所帮助,在此求一个star.项目地址: OrcasTeam/my-cli 接下来介绍一个打包编译过程中一个极为重要的工具--babel. ES6的枷锁 细心的朋友可以知道,在之前打包编译 ...

  5. 带你从零学ReactNative开发跨平台App开发(四)

    ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发 ...

  6. 带你从零学ReactNative开发跨平台App开发-[react native 仿boss直聘](十三)

    ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发 ...

  7. 带你从零学ReactNative开发跨平台App开发[expo 打包发布](八)

    ReactNative跨平台开发系列教程: 带你从零学ReactNative开发跨平台App开发(一) 带你从零学ReactNative开发跨平台App开发(二) 带你从零学ReactNative开发 ...

  8. 从头开始学JavaScript (四)——操作符

    原文:从头开始学JavaScript (四)--操作符 一.一元操作符 1.自增自减操作符:分为前置型和后置型: 前置型:++a;--a; 后置型:a++;a--; 例: <script typ ...

  9. C语言老司机学Python (五)

    今天看的是标准库概览. 操作系统接口: 用os模块实现. 针对文件和目录管理,还有个shutil模块可以用. 例句: import os os.getcwd() # 返回当前的工作目录 os.chdi ...

随机推荐

  1. Jenkins 安装简记录

    下载jenkins.war,放入tomcat 启动tomcat,如果console报错java.lang.OutOfMemoryError: PermGen space,则修改startup.bat( ...

  2. js原生函数

    arguments:代表所有的形参的集合: 可以通过arguments: cosole.log(arguments):打印所有参数 console.log(arguments[i]);可以通过访问下标 ...

  3. CentOs7 使用iptables防火墙开启关闭端口

    CentOs7 使用iptables防火墙开启关闭端口   # 0x01介绍 iptables命令是Linux上常用的防火墙软件,是netfilter项目的一部分iptables文件设置路径:命令:v ...

  4. Fuck me 忘记改REDO 造成复制用户超级慢

    . 一个用户的测试环境, 想着复制用户进行功能和单点性能测试. 但是用户数据量较大,见图 2. 发现在测试环境里面复制一个用户 大概耗时2小时20min的时间, 测试虚拟机的配置: 最开始注意到awr ...

  5. ESXi虚拟机开机进入bios的方法

    想要修改启动顺序, 发现界面比较难弄 应该是在设置里面有修正. 首先编辑设置 增加如下设置 就可以了.

  6. CPK公式

    CP:Cp = (USL-LSL)/6σ  USL上限值.LSL下限值.σ为产品特性值总体标准差: CPK:Cpk=Cp-|M-μ|/3σ  μ为产品特性值的总体均值,σ为产品特性值总体标准差,M為目 ...

  7. python 抽象类与接口类

    几个类 实现的方法都一致的话 就继承同一个父类 在父类写一个公共方法 给子类使用

  8. windows下 navicat_premium破解方法

    https://blog.csdn.net/qq_21205435/article/details/78902052

  9. ZJOI2019 Day1 题解

    想要继续向前,就从克服内心的恐惧开始. 麻将 题意 在麻将中,我们称点数连续的三张牌或三张点数一样的成为面子,称两张点数一样的牌为对子.一副十四张麻将牌的胡牌条件是可以分成四个面子和一个对子或者分成七 ...

  10. docker --swarm创建一个集群

    如果搭建错误可以强制脱离集群网络: docker swarm leave --force 初始化集群网络管理节点: docker swarm init --advertise-addr 10.101. ...