Go語言即時通訊系統開發日志day1,主要模擬實現的一個簡單的發送消息和接受消息的小demo,因為也才剛學習go語言的語法,對go的json、net/http庫了解不多,所以了解了一下go語言的encoding/json庫和net/http庫,以及websocket。
總結:實現了極簡的”聊天“demo,不能夠支持不同用戶的顯示,無單聊,群聊,未使用MySQL保存數據,Redis作為緩存。希望明天可以完成數據庫對數據存儲,支持雙人聊天,支持查看歷史聊天記錄。
學習方法反思:不要好高騖遠,只是完成了一個小demo,卻在學習過程找了一些github上的高星IM來看,卻實現不了,后續在完成聊天模塊,聯系人模塊,群組模塊等時可以在查看github的高星項目向其參考學習;不要追求完美,學習到一個知識點的時候,如json,http包,不要過多學習掌握即可,不用在瀏覽器中搜索過多頁面進行查看,僅選擇一倆個即可,最好可以寫一篇簡單的博客進行總結加深印象,使用ai也同樣,使用一個或兩個即可,不要過對比,浪費時間。
之前只是初略的了解了go語言支持json格式,但不了解作用是什么,以及json庫的作用;所以我寫了一個博客,Go語言:json 作用和語法,簡單介紹了 json 的作用(指定字段名、忽略空值、忽略字段),encoding/json的兩個常用函數Marshal
序列化和Unmarshal
反序列化。
定義消息類型
type Message struct {Sender string `json:"sender"`Content string `json:"content"`Timestamp int64 `json:"timestamp"`
}
構建服務器
func main() {// 初始化路由http.HandleFunc("/ws", handleConnections)// 添加靜態文件服務,用于測試HTML客戶端http.Handle("/", http.FileServer(http.Dir("./web")))// 啟動服務器log.Println("Server started on :8080")err := http.ListenAndServe(":8080", nil)if err != nil {log.Fatal("ListenAndServe: ", err)}
}var upgrater = websocket.Upgrader{ReadBufferSize: 1024,WriteBufferSize: 1024,
}// 客戶端連接
type Client struct {conn *websocket.Connsend chan []byte
}func handleConnections(w http.ResponseWriter, r *http.Request) {// 升級 HTTP 為 WebSocketconn, err := upgrater.Upgrade(w, r, nil)if err != nil {log.Println(err)return}defer conn.Close()// 創建客戶端client := &Client{conn: conn,send: make(chan []byte),}// 啟動讀寫goroutinego client.writePump()client.readPump()
}
-
每個客戶端連接由一個
Client
對象表示 -
每個連接使用兩個 goroutine 處理讀寫操作:
- 讀流程:
readPump
持續讀取消息 → 處理消息 → 可能通過client.send
發送響應 - 寫流程:其他 goroutine 向
client.send
發送數據 →writePump
將數據發送到 WebSocket
- 讀流程:
-
使用通道
client.send
在兩個 goroutine 之間傳遞消息
發送消息
func (c *Client) writePump() {defer c.conn.Close()for {select {case message, ok := <-c.send:if !ok {// 通道關閉c.conn.WriteMessage(websocket.CloseMessage, []byte{})return}if err := c.conn.WriteMessage(websocket.TextMessage, message); err != nil {log.Println("write error:", err)return}}}
}
WebSocket 客戶端的 “寫泵”(write pump) 函數,將消息從客戶端的發送通道 (c.send) 持續寫入 WebSocket 連接。
- 持續監聽
c.send
通道,一旦有消息就發送到 WebSocket 服務器 - 當通道關閉時,主動向服務器發送關閉消息并結束函數
- 處理發送過程中可能出現的錯誤
讀取消息
func (c *Client) readPump() {defer c.conn.Close()for {_, message, err := c.conn.ReadMessage()if err != nil {log.Println("read error:", err)break}// 處理接收到的消息log.Printf("Received: %s", message)}
}
WebSocket 客戶端的 “讀泵”(read pump) 功能,負責持續從服務器接收消息。
- 持續監聽 WebSocket 連接,讀取服務器發送的消息
- 處理讀取過程中出現的錯誤
- 將接收到的消息進行日志記錄或進一步處理
運行
-
確保項目結構如下:
im-go/ ├── main.go └── public/├── index.html└── client.js
-
安裝依賴:
go get github.com/gorilla/websocket
-
啟動服務器:
go run main.go
-
打開瀏覽器訪問:
http://localhost:8080
后端代碼
main.go
package mainimport ("log""net/http""github.com/gorilla/websocket"
)type Message struct {Sender string `json:"sender"`Content string `json:"content"`Timestamp int64 `json:"timestamp"`
}func main() {// 初始化路由http.HandleFunc("/ws", handleConnections)// 添加靜態文件服務,用于測試HTML客戶端http.Handle("/", http.FileServer(http.Dir("./web")))// 啟動服務器log.Println("Server started on :8080")err := http.ListenAndServe(":8080", nil)if err != nil {log.Fatal("ListenAndServe: ", err)}
}var upgrater = websocket.Upgrader{ReadBufferSize: 1024,WriteBufferSize: 1024,
}// 客戶端連接
type Client struct {conn *websocket.Connsend chan []byte
}func handleConnections(w http.ResponseWriter, r *http.Request) {// 升級 HTTP 為 WebSocketconn, err := upgrater.Upgrade(w, r, nil)if err != nil {log.Println(err)return}defer conn.Close()// 創建客戶端client := &Client{conn: conn,send: make(chan []byte),}// 啟動讀寫goroutinego client.writePump()client.readPump()
}func (c *Client) readPump() {defer c.conn.Close()for {_, message, err := c.conn.ReadMessage()if err != nil {log.Println("read error:", err)break}// 處理接收到的消息log.Printf("Received: %s", message)}
}func (c *Client) writePump() {defer c.conn.Close()for {select {case message, ok := <-c.send:if !ok {// 通道關閉c.conn.WriteMessage(websocket.CloseMessage, []byte{})return}if err := c.conn.WriteMessage(websocket.TextMessage, message); err != nil {log.Println("write error:", err)return}}}
}
前端代碼
前端代碼雖然是ai生成的,我還是看了 3小時前端入門教程(HTML+CSS+JS),了解了一下這三者是什么,以及作用
HTML(超文本標記語言)
- 是什么:
HTML 是網頁的??結構和內容層??,通過標簽(如<h1>
、<p>
、<div>
)定義頁面的文本、圖片、鏈接等元素。 - 作用:
- 搭建網頁的骨架(例如標題、段落、表單)。
- 提供語義化結構(如
<header>
、<article>
),便于搜索引擎和屏幕閱讀器理解。
CSS(層疊樣式表)
- 是什么:
CSS 是網頁的??表現層??,控制 HTML 元素的外觀(顏色、布局、字體等)。 - 作用:
- 美化頁面(如響應式設計、動畫效果)。
- 實現布局(Flexbox、Grid 等)。
JavaScript(JS)
- 是什么:
JavaScript 是網頁的??行為層??,一種編程語言,用于實現交互和動態功能。 - 作用:
- 處理用戶操作(點擊、輸入等)。
- 動態更新內容(如加載數據、DOM 操作)。
- 與后端交互(通過 AJAX 或 Fetch API)。
后續的話前端可能就用ai生成vue的了
Vue 是什么?
一個用于構建用戶界面的 JavaScript 框架,核心特點是:
- 響應式數據:數據變,視圖自動更新。
- 組件化:把頁面拆成可復用的組件。
- 易上手:類似 HTML 的模板語法,學習成本低。
Vue 的作用
- 替代 jQuery,動態交互更簡單(如實時搜索、表單驗證)。
- 開發單頁應用(SPA)(如后臺管理系統)。
- 搭配插件(Vue Router、Pinia)做復雜項目。
index.html
<!DOCTYPE html>
<html><head><title>Go Chat Demo</title><script src="client.js"></script>
</head><body><h1>Go Chat Demo</h1><div id="messages" style="height:300px;overflow:auto;border:1px solid #ccc;"></div><input type="text" id="messageInput" placeholder="Type a message..."><button onclick="sendMessage()">Send</button>
</body></html>
client.js
var ws;function connect() {ws = new WebSocket("ws://" + window.location.host + "/ws");ws.onopen = function () {console.log("Connected to server");addMessage("System: Connected to server");};ws.onmessage = function (event) {console.log("Message received:", event.data);addMessage("Server: " + event.data);};ws.onclose = function () {console.log("Disconnected from server");addMessage("System: Disconnected from server");// 嘗試5秒后重連setTimeout(connect, 5000);};ws.onerror = function (err) {console.log("WebSocket error:", err);};
}function addMessage(msg) {var messages = document.getElementById("messages");messages.innerHTML += "<p>" + msg + "</p>";messages.scrollTop = messages.scrollHeight;
}function sendMessage() {var input = document.getElementById("messageInput");var message = input.value;if (message && ws.readyState === WebSocket.OPEN) {ws.send(message);addMessage("You: " + message);input.value = "";}
}// 頁面加載時連接
window.onload = connect;