http://www.open-open.com/lib/view/open1416379948711.html

这个示例应用程序展示了如何使用 WebSocketGolang 和 jQuery 创建一个简单的web聊天应用程序。这个示例的源代码在 https://github.com/waylau/goChat 。

Running the example 运行示例

这个示例需要 Golang 开发环境。 该页面描述如何安装开发环境。

一旦你去启动和运行,您可以下载、构建和运行的例子, 使用命令:

go get gary.burd.info/go-websocket-chat
go-websocket-chat

在支持 websocket 的浏览器尝试打开 http://127.0.0.1:8080/ 启动应用

Server 服务器

服务器程序实现了 http 包,包含了 Go 分发和 Gorilla 项目的 websocket 包.

应用程序定义了两种类型, connection 和 hub 。服务器为每个 webscocket 连接 创建的一个 connection 类型的实例 。 连接器扮演了 websocket 和 hub 类型单例 之间的媒介 。 hub 保持一组注册了的连接器 和 广播到连接器的信息。

程序运行了一个 goroutine 给 hub 和两个 goroutine 给每个连接器。 goroutine 通过 channel 和其他进行交流。 hub 拥有注册连接器、注销连接器和广播信息的 channel。一个连机器拥有缓存的发出信息的 channel 。其中一个 连接器的 goroutine 从这个 channel 中读信息 并把信息写入 webscoket。另外一个连接器 goroutine 从 websocket 读信息,并把信息发送到 hub。

下面是 hub 类型代码:

package main

type hub struct {
// 注册了的连接器
connections map[*connection]bool // 从连接器中发入的信息
broadcast chan []byte // 从连接器中注册请求
register chan *connection // 从连接器中注销请求
unregister chan *connection
} var h = hub{
broadcast: make(chan []byte),
register: make(chan *connection),
unregister: make(chan *connection),
connections: make(map[*connection]bool),
} func (h *hub) run() {
for {
select {
case c := <-h.register:
h.connections[c] = true
case c := <-h.unregister:
if _, ok := h.connections[c]; ok {
delete(h.connections, c)
close(c.send)
}
case m := <-h.broadcast:
for c := range h.connections {
select {
case c.send <- m:
default:
delete(h.connections, c)
close(c.send)
}
}
}
}
}

应用程序的 主要 函数启动 hub 以 goroutine 形式运行方法。连接器 发送请求到 hub 通过 注册、注销和广播 channel。

hub 注册连接器通过添加 connection 的指针作为 connections map 的主键。这个 map 的值通常是 true。

注销的代码有点复杂。除了从 connections map 删除连接器的指针外, hub 关闭了 connection 的发送,来标识没有信息再被发送到 connection了。

hub 通过循环注册连接器和发送信息到连接器的发送 channel 来控制信息。 如果连接器的发送缓冲区已经满了,那么 hub 假设 客户端已死或卡住了。这种情况下, hub 注销连接器 并关闭 websocket.

下面关于 connection 类型的代码:

package main

import (
"github.com/gorilla/websocket"
"net/http"
) type connection struct {
// websocket 连接器
ws *websocket.Conn // 发送信息的缓冲 channel
send chan []byte
} func (c *connection) reader() {
for {
_, message, err := c.ws.ReadMessage()
if err != nil {
break
}
h.broadcast <- message
}
c.ws.Close()
} func (c *connection) writer() {
for message := range c.send {
err := c.ws.WriteMessage(websocket.TextMessage, message)
if err != nil {
break
}
}
c.ws.Close()
} var upgrader = &websocket.Upgrader{ReadBufferSize: 1024, WriteBufferSize: 1024} func wsHandler(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
c := &connection{send: make(chan []byte, 256), ws: ws}
h.register <- c
defer func() { h.unregister <- c }()
go c.writer()
c.reader()
}

wsHandler 方法被主函数当做http handler注册。HTTP 连接到 WebSocket 协议的升级,创建一个连接对象,注册这个连接到 sub ,并通过 defer延迟语句 来控制 连接的注销。

接着,wsHandler 方法开启 连接器的写入方法作为一个 goroutine。 写入方法将信息从连接器的 channel 转入 websocket。当 hub 关闭 channel 或者 在写入 websocket 时出错,写入方法关闭。

最后,wsHandler 方法 调用连接器的 读 方法。 读方法将 入站消息 从 websocket 转到 hub。

这里是服务器的代码的其余部分:

package main

import (
"flag"
"go/build"
"log"
"net/http"
"path/filepath"
"text/template"
) var (
addr = flag.String("addr", ":8080", "http service address")
assets = flag.String("assets", defaultAssetPath(), "path to assets")
homeTempl *template.Template
) func defaultAssetPath() string {
p, err := build.Default.Import("gary.burd.info/go-websocket-chat", "", build.FindOnly)
if err != nil {
return "."
}
return p.Dir
} func homeHandler(c http.ResponseWriter, req *http.Request) {
homeTempl.Execute(c, req.Host)
} func main() {
flag.Parse()
homeTempl = template.Must(template.ParseFiles(filepath.Join(*assets, "home.html")))
go h.run()
http.HandleFunc("/", homeHandler)
http.HandleFunc("/ws", wsHandler)
if err := http.ListenAndServe(*addr, nil); err != nil {
log.Fatal("ListenAndServe:", err)
}
}

应用主程序启动 hub goroutine。 接着 主程序 注册 主页 和 websocket 连接器的控制器N。最后主程序启动 HTTP 服务器。

Client 客户端

客户端的实现是一个简单的 HTML 文件:

<html>
<head>
<title>Chat Example</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript">
$(function() { var conn;
var msg = $("#msg");
var log = $("#log"); function appendLog(msg) {
var d = log[0]
var doScroll = d.scrollTop == d.scrollHeight - d.clientHeight;
msg.appendTo(log)
if (doScroll) {
d.scrollTop = d.scrollHeight - d.clientHeight;
}
} $("#form").submit(function() {
if (!conn) {
return false;
}
if (!msg.val()) {
return false;
}
conn.send(msg.val());
msg.val("");
return false
}); if (window["WebSocket"]) {
conn = new WebSocket("ws://{{$}}/ws");
conn.onclose = function(evt) {
appendLog($("<div><b>Connection closed.</b></div>"))
}
conn.onmessage = function(evt) {
appendLog($("<div/>").text(evt.data))
}
} else {
appendLog($("<div><b>Your browser does not support WebSockets.</b></div>"))
}
});
</script>
<style type="text/css">
html {
overflow: hidden;
} body {
overflow: hidden;
padding: 0;
margin: 0;
width: 100%;
height: 100%;
background: gray;
} #log {
background: white;
margin: 0;
padding: 0.5em 0.5em 0.5em 0.5em;
position: absolute;
top: 0.5em;
left: 0.5em;
right: 0.5em;
bottom: 3em;
overflow: auto;
} #form {
padding: 0 0.5em 0 0.5em;
margin: 0;
position: absolute;
bottom: 1em;
left: 0px;
width: 100%;
overflow: hidden;
} </style>
</head>
<body>
<div id="log"></div>
<form id="form">
<input type="submit" value="Send" />
<input type="text" id="msg" size="64"/>
</form>
</body>
</html>

客户端使用 jQuery

文档加载。脚本检查 websocket 的功能 。如果 WebSocket 功能 可以用,然后打开脚本与服务器的连接,并注册一个回调处理来自服务器的信息。回调使用 appendlog 方法将消息添加到聊天记录。

appendlog 方法检查在添加新的内容时的滚动位置,从而可以让用户手动滚动聊天记录而不会被新来的消息中断。如果聊天记录滚动至底部,那么新内容添加的到旧内容的后面。否则,滚动的位置不会改变。

表单处理器将用户的输入写入到 WebSocket 并且清除输入字段。

参考:http://gary.burd.info/go-websocket-chat

来自:http://www.waylau.com/go-websocket-chat/

WebSocket 和 Golang 实现聊天功能的更多相关文章

  1. WebSocket(3)---实现一对一聊天功能

    实现一对一聊天功能 功能介绍:实现A和B单独聊天功能,即A发消息给B只能B接收,同样B向A发消息只能A接收. 本篇博客是在上一遍基础上搭建,上一篇博客地址:[WebSocket]---实现游戏公告功能 ...

  2. Spring Websocket实现简易在线聊天功能

    针对Spring Websocket的实现,我参照了其他博主的文章https://www.cnblogs.com/leechenxiang/p/5306372.html 下面直接给出实现: 一.引入相 ...

  3. webSocket实现多人聊天功能

    webSocket实现多人在线聊天 主要思路如下: 1.使用vue构建简单的聊天室界面 2.基于nodeJs 的webSocket开启一个socket后台服务,前端使用H5的webSocket来创建一 ...

  4. Spring 学习——基于Spring WebSocket 和STOMP实现简单的聊天功能

    本篇主要讲解如何使用Spring websocket 和STOMP搭建一个简单的聊天功能项目,里面使用到的技术,如websocket和STOMP等会简单介绍,不会太深,如果对相关介绍不是很了解的,请自 ...

  5. 使用websocket实现在线聊天功能

    很早以前为了快速达到效果,使用轮询实现了在线聊天功能,后来无意接触了socket,关于socket我的理解是进程间通信,首先要有服务器跟客户端,服务的启动监听某ip端口定位该进程,客户端开启socke ...

  6. spring boot集成websocket实现聊天功能和监控功能

    本文参考了这位兄台的文章: https://blog.csdn.net/ffj0721/article/details/82630134 项目源码url: https://github.com/zhz ...

  7. 基于vs2015 SignalR开发的微信小程序使用websocket实现聊天功能

    一)前言 在微信小程上实现聊天功能,大致有三种方式:1)小程序云开发 2)购买第三方IM服务 3)使用自己的服务器自己开发. 这里重要讲使用自己的服务器自己开发,并且是基于vs的开发. 网上提供的解决 ...

  8. JAVA结合WebSocket实现简单客服聊天功能

    说明:该示例只简单的实现了客服聊天功能. 1.聊天记录没有保存到数据库中,一旦服务重启,消息记录将会没有,如果需要保存到数据库中,可以扩展 2.页面样式用的网上模板,样式可以自己进行修改 3.只能由用 ...

  9. 【WebSocket No.2】WebSocket和Socket实现聊天群发

    介绍: 前面写过一篇简单的websocke实现服务端.这一篇就不在说什么基础的东西主要是来用实例说话,主要是讲一下实现单聊和群组聊天和所有群发的思路设计. 直接不懂的可以看一下上一篇简单版本再来看也行 ...

随机推荐

  1. www-authenticate与BASE-64认证技术

    www-authenticate是一种简单的用户身份认证技术.很多验证都采用这种验证方式,尤其在嵌入式领域中.优点:方便缺点:这种认证方式在传输过程中采用的用户名密码加密方式为BASE-64,其解码过 ...

  2. XML解析之sax解析案例(一)读取contact.xml文件,完整输出文档内容

    一.新建Demo2类: import java.io.File; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXPar ...

  3. Caffe框架,图像数据转换成LMDB数据格式

    小码农最近在研究深度学习,对所学知识做点记录,以供以后翻阅.在Caffe框架中,数据的格式都是LMDB的,如何将图像数据转换成这个格式呢? 首先,将图像数据和标签生成txt文档,执行一下代码: fin ...

  4. 经过一段的努力,终于成为CSDN博客专家,感谢大家支持

    感谢CSDN提供这么好的一个技术学习平台,通过各路大神的博客我成长了许多,同时也感谢支持我的朋友们,我会继续努力,用心去写好博客.还请继续关注我~ 谢谢!

  5. C++对象模型(一):The Semantics of Constructors The Default Constructor (默认构造函数什么时候会被创建出来)

    本文是 Inside The C++ Object Model, Chapter 2的部分读书笔记. C++ Annotated Reference Manual中明确告诉我们: default co ...

  6. 阿里云服务器实战(一) : 在Linux下Tomcat7下使用连接池

    云服务器 的环境如下: Tomcat7+MySql5.6 一,如果自定义了程序的文件目录 , 下面的/alidata/xxx 就是自定义的目录 在Linux的Tomcat的server.xml里的Ho ...

  7. Spring揭秘 读书笔记 四----方法注入

    我们知道,拥有prototype类型scope的bean,在请求方每次向容器请求该类型对象的时候,容器都会返回一个全新的该对象实例. 我们看下面的例子: public class MockNewsPe ...

  8. iOS开发支付集成之微信支付

    这一篇是<iOS开发之支付>这一部分的继支付宝支付集成,银联支付集成第三篇,微信支付.在集成的时候建议都要去下载最新版的SDK,因为我知道的前不久支付宝,银联都更新了一次,微信的不太清楚更 ...

  9. Saiku去掉登录模块

    1.修改applicationContext-saiku-webapp.xml <security:intercept-url pattern="/rest/**" acce ...

  10. 典型分布式系统分析: GFS

    本文是典型分布式系统分析系列的第二篇,关注的是GFS,一个分布式文件存储系统.在前面介绍MapReduce的时候也提到,MapReduce的原始输入文件和最终输出都是存放在GFS上的,GFS保证了数据 ...