四时宝库

程序员的知识宝库

GO语言120行代码实现websocket多人聊天

今天跟大家分享一个GO语言webscoket多人聊天室,这个需要有一定的GO基础,关于websocket的基础知识,大家可以移步到之前发的两篇文章。

如果大家觉得GO语言不了解的话,也可以在下方留言,后续推出GO语言系列学习分享。

websocket.go 代码

// WebChat project websocket.go
package main
import (
 "fmt"
 "net/http"
 "time"
 "encoding/json"
 "strings"
 "github.com/golang/net/websocket"
)
// 全局信息
var datas Datas
var users map[*websocket.Conn]string
type UserMsg struct {
 UserName string
 Msg string
 DataType string
}
type UserData struct {
 UserName string
}
type Datas struct {
 UserMsgs []UserMsg
 UserDatas []UserData
}
func main() {
 fmt.Println("启动时间")
 fmt.Println(time.Now())
 //初始化
 datas = Datas{}
 users = make(map[*websocket.Conn]string)
 //绑定效果页面
 http.HandleFunc("/", h_index)
 //绑定socket方法
 http.Handle("/webSocket", websocket.Handler(h_webSocket))
 //开始监听
 http.ListenAndServe(":8888", nil)
}
// websocket H5页面
func h_index(w http.ResponseWriter, r *http.Request) {
 http.ServeFile(w, r, "index.html")
}
// 服务端程序
func h_webSocket(ws *websocket.Conn) {
 var userMsg UserMsg
 var data string
 for {
 //判断是否重复连接
 if _, ok := users[ws]; !ok {
 users[ws] = "匿名"
 }
 userMsgsLen := len(datas.UserMsgs)
 fmt.Println("ws:", ws, "UserMsgs", userMsgsLen, "users长度:", len(users))
 //有消息时,全部分发送数据
 if userMsgsLen > 0 {
 b, errMarshl := json.Marshal(datas)
 if errMarshl != nil {
 fmt.Println("全局消息内容异常...")
 break
 }
 for key, _ := range users {
 errMarshl = websocket.Message.Send(key, string(b))
 if errMarshl != nil {
 //移除出错的链接
 delete(users, key)
 fmt.Println("发送出错...")
 break
 }
 }
 datas.UserMsgs = make([]UserMsg, 0)
 }
 fmt.Println("开始解析数据...")
 err := websocket.Message.Receive(ws, &data)
 fmt.Println("data:", data)
 if err != nil {
 //移除出错的链接
 delete(users, ws)
 fmt.Println("接收出错...")
 break
 }
 data = strings.Replace(data, "\n", "", 0)
 err = json.Unmarshal([]byte(data), &userMsg)
 if err != nil {
 fmt.Println("解析数据异常...")
 break
 }
 fmt.Println("请求数据类型:", userMsg.DataType)
 switch userMsg.DataType {
 case "send":
 //赋值对应的昵称到ws
 if _, ok := users[ws]; ok {
 users[ws] = userMsg.UserName
 //清除连接人昵称信息
 datas.UserDatas = make([]UserData, 0)
 //重新加载当前在线连接人
 for _, item := range users {
 userData := UserData{UserName: item}
 datas.UserDatas = append(datas.UserDatas, userData)
 }
 }
 datas.UserMsgs = append(datas.UserMsgs, userMsg)
 }
 }
}

GO监听HTTP端口是 8888,webSocket目录是绑定的websokcet服务器目录,根目录/ 是H5页面,用来连接websocket服务器。

websocket.go代码运行效果:

H5页面

<!DOCTYPE html>
<html lang="zh-CN">
<head>
 <title>Go Websocket多人聊天室</title>
 <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
 <!-- 新 Bootstrap 核心 CSS 文件 -->
 <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
 <script src="//cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
 <!--<script src="//cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>-->
</head>
<body>
<div class="container">
 <div>内容:</div>
 <div class="list-group" id="divShow">
 <!--<div class="list-group-item list-group-item-success">1111</div>
 <div class="list-group-item list-group-item-info">1111</div>
 <div class="list-group-item list-group-item-warning">1111</div>
 <div class="list-group-item list-group-item-danger">1111</div>-->
 </div>
 <div class="list-group" id="divUsers">
 在线:<br />
 <!--<div class="btn btn-default">111</div>-->
 </div>
 <div>
 昵称:<input class="form-control" id="txtUserName" value="游客" type="text" maxlength="20" style="width: 30%; margin-bottom: 15px" />
 聊聊:<textarea class="form-control" id="txtContent" autofocus rows="6" placeholder="想聊的内容" maxlength="200" required style="width: 60%; "></textarea>
 <button class="btn btn-default" id="btnSend" style="margin-top:15px">发 送</button>
 </div>
</div>
</body>
</html>
<script>
 var tool = function () {
 var paperLoopNum = 0;
 var paperTempleArr = [
 '<div class="list-group-item list-group-item-success">{0}</div>',
 '<div class="list-group-item list-group-item-info">{0}</div>',
 '<div class="list-group-item list-group-item-warning">{0}</div>',
 '<div class="list-group-item list-group-item-danger">{0}</div>'
 ];
 return {
 paperDiv: function (val) {
 var hl = paperTempleArr[paperLoopNum];
 paperLoopNum++;
 if (paperLoopNum >= paperTempleArr.length) { paperLoopNum = 0; }
 return this.formart(hl, [val])
 },
 formart: function (str, arrVal) {
 for (var i = 0; i < arrVal.length; i++) {
 str = str.replace("{" + i + "}", arrVal[i]);
 }
 return str;
 }
 }
 }
 function showMsg(id, hl, isAppend) {
 if (!isAppend) { $("#" + id).html(hl); } else {
 $("#" + id).append(hl);
 }
 }
 $(function () {
 //初始化工具方法
 var tl = new tool();
 var wsUrl = "ws://127.0.0.1:8888/webSocket";
 ws = new WebSocket(wsUrl);
 try {
 ws.onopen = function () {
 //showMsg("divShow", tl.paperDiv("连接服务器-成功"));
 }
 ws.onclose = function () {
 if (ws) {
 ws.close();
 ws = null;
 }
 showMsg("divShow", tl.paperDiv("连接服务器-关闭"), true);
 }
 ws.onmessage = function (result) {
 //console.log(result.data);
 var data = JSON.parse(result.data);
 $(data.UserMsgs).each(function (i, item) {
 showMsg("divShow", tl.paperDiv("【" + item.UserName + "】:" + item.Msg), true);
 });
 var userDataShow = [];
 $(data.UserDatas).each(function (i, item) {
 userDataShow.push('<div class="btn btn-default">' + item.UserName + '</div>');
 });
 showMsg("divUsers", userDataShow.join(''), false);
 }
 ws.onerror = function () {
 if (ws) {
 ws.close();
 ws = null;
 }
 showMsg("divShow", tl.paperDiv("连接服务器-关闭"), true);
 }
 } catch (e) {
 alert(e.message);
 }
 $("#btnSend").on("click", function () {
 var tContentObj = $("#txtContent");
 var tContent = $.trim( tContentObj.val()).replace("/[\n]/g", "");
 var tUserName = $.trim( $("#txtUserName").val()); tUserName = tUserName.length <= 0 ? "匿名" : tUserName;
 if (tContent.length <= 0 || $.trim(tContent).length <= 0) { alert("请输入发送内容!"); return; }
 if (ws == null) { alert("连接失败,请F5刷新页面!"); return; }
 var request = tl.formart('{"UserName": "{0}", "DataType": "{1}", "Msg": "{2}" }',
 [tUserName, "send", tContent]);
 ws.send(request);
 tContentObj.val("");
 tContentObj.val($.trim(tContentObj.val()).replace("/[\n]/g", ""));
 });
 $("#txtContent").on("keydown", function (event) {
 if (event.keyCode == 13) {
 $("#btnSend").trigger("click");
 }
 });
 })
</script>

多人聊天室效果

首先打开 http://localhost:8888/ ,然后就可以发消息进行聊天了,这里打开两个页面做测试,实际效果如下:

服务端输出:

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接