原文地址:
http://www.niu12.com/article/3
websocket+golang聊天室
main.go和index.html放在同一目錄下
main.go
package main
import (
"encoding/json"
"fmt"
"golang.org/x/net/websocket"
"net/http"
"time"
)
type Message struct {
Username string
Message string
}
type User struct {
Username string
}
type Datas struct {
Messages []Message
Users []User
}
// 全局信息
var datas Datas
var users map[*websocket.Conn]string
func main() {
fmt.Println("啟動時間: ", time.Now())
// 初始化數據
datas = Datas{}
users = make(map[*websocket.Conn]string)
// 渲染頁面
http.HandleFunc("/", index)
// 監聽socket方法
http.Handle("/webSocket", websocket.Handler(webSocket))
// 監聽8080端口
http.ListenAndServe(":8889", nil)
}
func index(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "index.html")
}
func webSocket(ws *websocket.Conn) {
var message Message
var data string
for {
// 接收數據
err := websocket.Message.Receive(ws, &data)
if err != nil {
// 移除出錯的連接
delete(users, ws)
fmt.Println("連接異常")
break
}
// 解析信息
err = json.Unmarshal([]byte(data), &message)
if err != nil {
fmt.Println("解析數據異常")
}
// 添加新用戶到map中,已經存在的用戶不必添加
if _, ok := users[ws]; !ok {
users[ws] = message.Username
// 添加用戶到全局信息
datas.Users = append(datas.Users, User{Username:message.Username})
}
// 添加聊天記錄到全局信息
datas.Messages = append(datas.Messages, message)
// 通過webSocket將當前信息分發
for key := range users{
err := websocket.Message.Send(key, data)
if err != nil{
// 移除出錯的連接
delete(users, key)
fmt.Println("發送出錯: " + err.Error())
break
}
}
}
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="icon" href="./favicon.ico" type="image/x-icon" />
<title>H5聊天室</title>
<style type="text/css">
.talk_con {
width: 100%;
height: 100%;
border: 1px solid #666;
margin: 50px auto 0;
background: #f9f9f9;
}
.talk_show {
width: 100%;
height: 420px;
border: 1px solid #666;
background: #fff;
margin: 10px auto 0;
overflow: auto;
}
.talk_input {
width: 100%;
}
.talk_word {
width: 90%;
height: 26px;
float: left;
text-indent: 10px;
margin: 2% 5%;
}
.talk_sub {
width: 100%;
height: 30px;
float: left;
}
.atalk {
margin: 10px;
}
.atalk span {
display: inline-block;
background: #0181cc;
border-radius: 10px;
color: #fff;
padding: 5px 10px;
}
.btalk {
margin: 10px;
text-align: right;
}
.btalk span {
display: inline-block;
background: #ef8201;
border-radius: 10px;
color: #fff;
padding: 5px 10px;
}
</style>
<script src="//cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
<script type="text/javascript">
$(function () {
// 詢問框獲取用戶昵稱
let username = localStorage.getItem("username") ?
localStorage.getItem("username") : disp_prompt();
let words = $("#words");
let talkWords = $("#talkwords");
let talkSubmit = $("#talksub");
// webSocket
let wsURL = "ws://chat.niu12.com/webSocket";
ws = new WebSocket(wsURL);
try {
// 監聽連接服務器
ws.onopen = function () {
console.log("已連接服務器")
};
// 監聽關閉服務器
ws.onclose = function () {
if (ws) {
ws.close();
ws = null
}
console.log("關閉服務器連接")
};
// 監聽信息
ws.onmessage = function (result) {
let data = JSON.parse(result.data);
let className = "atalk";
let user = data.username
// 如果是本人,放在右邊 不是本人 放在左邊
if (data.username === username){
className = "btalk";
user = "";
}
str = words.html() +
'<div class=" + className + ">'+user+'<span>'
+ data.message + '</span></div>';
words.html(str);
var scrollHeight = words.prop("scrollHeight");
words.scrollTop(scrollHeight);
};
// 監聽錯誤
ws.onerror = function () {
if (ws) {
ws.close();
ws = null;
}
console.log("服務器連接失敗")
}
} catch (e) {
console.log(e.message)
}
document.onkeydown = function (event) {
let e = event || window.event;
if (e && e.keyCode === 13) { //回車鍵的鍵值為13
talkSubmit.click()
}
};
talkSubmit.click(function () {
// 獲取輸入框內容
let content = talkWords.val();
if (content === "") {
// 消息為空時彈窗
alert("消息不能為空");
return;
}
// 發送數據
if (ws == null){
alert("連接服務器失敗,請刷新頁面");
window.location.reload();
return
}
let request = {"username":username, "message":content};
ws.send(JSON.stringify(request));
// 清空輸入框
talkWords.val("")
})
});
function disp_prompt() {
let username = prompt("請輸入昵稱");
if (username == null || username === "") {
disp_prompt()
}else {
localStorage.setItem("username", username);
return username;
}
}
</script>
</head>
<body>
<h1>簡易聊天室</h1>
<div class="talk_con">
<div class="talk_show" id="words">
</div>
<div class="talk_input">
<input type="text" class="talk_word" id="talkwords" placeholder="輸入聊天內容">
<input type="button" value="發送" class="talk_sub" id="talksub">
</div>
</div>
</body>
</html>