欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

使用Go語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單聊天系統(tǒng)

 更新時(shí)間:2024年10月05日 09:55:43   作者:小于負(fù)無(wú)窮  
本文介紹了如何使用Go語(yǔ)言和WebSocket技術(shù)構(gòu)建一個(gè)簡(jiǎn)單的多人聊天室系統(tǒng),包括客戶端連接管理、消息廣播和并發(fā)處理,最后,通過(guò)編寫main.go、hub.go和client.go等核心代碼模塊,具有一定的參考價(jià)值,感興趣的可以了解一下

在互聯(lián)網(wǎng)時(shí)代,聊天系統(tǒng)是常見(jiàn)的應(yīng)用場(chǎng)景之一。無(wú)論是即時(shí)通訊、在線客服還是多人游戲中的消息系統(tǒng),聊天功能的實(shí)現(xiàn)都是必不可少的。本文將使用 Go 語(yǔ)言,結(jié)合 WebSocket 來(lái)構(gòu)建一個(gè)簡(jiǎn)單的多人聊天室系統(tǒng)。

一、項(xiàng)目結(jié)構(gòu)

首先,我們?cè)O(shè)計(jì)一個(gè)簡(jiǎn)單的項(xiàng)目結(jié)構(gòu),文件結(jié)構(gòu)如下:

go-chat/
│
├── main.go          // 主程序
├── client.go        // 處理客戶端連接
└── hub.go           // 消息管理

WebSocket 簡(jiǎn)介

WebSocket 是一種基于 TCP 的網(wǎng)絡(luò)協(xié)議,允許客戶端和服務(wù)端建立持久的全雙工通信連接。相比于傳統(tǒng)的 HTTP 請(qǐng)求-響應(yīng)模型,WebSocket 更加適合實(shí)時(shí)通信場(chǎng)景,因此它是實(shí)現(xiàn)聊天系統(tǒng)的理想選擇。

二、實(shí)現(xiàn)思路

  • 客戶端連接管理:每個(gè)客戶端通過(guò) WebSocket 連接到服務(wù)器,服務(wù)器會(huì)為每個(gè)連接的客戶端分配一個(gè)唯一的 connection
  • 消息廣播:當(dāng)某個(gè)客戶端發(fā)送消息時(shí),服務(wù)器將該消息廣播給所有連接的客戶端。
  • 并發(fā)處理:Go 原生支持并發(fā)編程,通過(guò) Goroutine 和 Channel 可以輕松處理并發(fā)消息傳遞。

三、詳細(xì)實(shí)現(xiàn)

1. main.go - 啟動(dòng) WebSocket 服務(wù)

package main

import (
    "log"
    "net/http"
)

func main() {
    hub := newHub()
    go hub.run()

    http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
        serveWs(hub, w, r)
    })

    log.Println("服務(wù)器啟動(dòng),監(jiān)聽端口 8080...")
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("監(jiān)聽失敗:", err)
    }
}

main.go 文件的作用是啟動(dòng) HTTP 服務(wù)器,并在 /ws 路徑上處理 WebSocket 連接請(qǐng)求。

2. hub.go - 消息管理中心

Hub 負(fù)責(zé)管理所有的客戶端連接,以及消息的廣播。

package main

// Hub 負(fù)責(zé)管理所有客戶端的注冊(cè)、注銷及消息廣播
type Hub struct {
    clients    map[*Client]bool // 已連接的客戶端
    broadcast  chan []byte      // 從客戶端接收的廣播消息
    register   chan *Client     // 注冊(cè)請(qǐng)求
    unregister chan *Client     // 注銷請(qǐng)求
}

func newHub() *Hub {
    return &Hub{
        clients:    make(map[*Client]bool),
        broadcast:  make(chan []byte),
        register:   make(chan *Client),
        unregister: make(chan *Client),
    }
}

func (h *Hub) run() {
    for {
        select {
        case client := <-h.register:
            h.clients[client] = true
        case client := <-h.unregister:
            if _, ok := h.clients[client]; ok {
                delete(h.clients, client)
                close(client.send)
            }
        case message := <-h.broadcast:
            for client := range h.clients {
                select {
                case client.send <- message:
                default:
                    close(client.send)
                    delete(h.clients, client)
                }
            }
        }
    }
}
  • clients:保存當(dāng)前連接的所有客戶端。
  • broadcast:一個(gè)通道,用于廣播消息給所有客戶端。
  • register/unregister:用于客戶端連接和斷開的注冊(cè)和注銷。

3. client.go - 處理客戶端連接

每個(gè)客戶端的連接由 Client 結(jié)構(gòu)體表示,并包含了 WebSocket 連接和發(fā)送消息的通道。

package main

import (
    "github.com/gorilla/websocket"
    "log"
    "net/http"
    "time"
)

const (
    writeWait = 10 * time.Second
    pongWait  = 60 * time.Second
    pingPeriod = (pongWait * 9) / 10
)

var upgrader = websocket.Upgrader{
    ReadBufferSize:  1024,
    WriteBufferSize: 1024,
}

type Client struct {
    hub  *Hub
    conn *websocket.Conn
    send chan []byte
}

func serveWs(hub *Hub, w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Println("升級(jí)到 WebSocket 失敗:", err)
        return
    }
    client := &Client{hub: hub, conn: conn, send: make(chan []byte, 256)}
    client.hub.register <- client

    go client.writePump()
    go client.readPump()
}

func (c *Client) readPump() {
    defer func() {
        c.hub.unregister <- c
        c.conn.Close()
    }()
    c.conn.SetReadLimit(512)
    c.conn.SetReadDeadline(time.Now().Add(pongWait))
    c.conn.SetPongHandler(func(string) error { c.conn.SetReadDeadline(time.Now().Add(pongWait)); return nil })

    for {
        _, message, err := c.conn.ReadMessage()
        if err != nil {
            if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
                log.Printf("讀取錯(cuò)誤: %v", err)
            }
            break
        }
        c.hub.broadcast <- message
    }
}

func (c *Client) writePump() {
    ticker := time.NewTicker(pingPeriod)
    defer func() {
        ticker.Stop()
        c.conn.Close()
    }()

    for {
        select {
        case message, ok := <-c.send:
            c.conn.SetWriteDeadline(time.Now().Add(writeWait))
            if !ok {
                c.conn.WriteMessage(websocket.CloseMessage, []byte{})
                return
            }

            w, err := c.conn.NextWriter(websocket.TextMessage)
            if err != nil {
                return
            }
            w.Write(message)

            n := len(c.send)
            for i := 0; i < n; i++ {
                w.Write(<-c.send)
            }

            if err := w.Close(); err != nil {
                return
            }

        case <-ticker.C:
            c.conn.SetWriteDeadline(time.Now().Add(writeWait))
            if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
                return
            }
        }
    }
}
  • serveWs:處理每個(gè) WebSocket 連接請(qǐng)求,并為每個(gè)連接創(chuàng)建一個(gè)客戶端實(shí)例。
  • readPump:從 WebSocket 連接中讀取消息,并將消息廣播到所有客戶端。
  • writePump:負(fù)責(zé)將消息發(fā)送給客戶端,并定期發(fā)送心跳檢測(cè)(ping)消息以保持連接。

四、運(yùn)行項(xiàng)目

首先,安裝 WebSocket 依賴:

go get github.com/gorilla/websocket

編寫前端 HTML 頁(yè)面(可用于測(cè)試),例如 index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Go 聊天室</title>
</head>
<body>
    <div id="chatbox"></div>
    <input id="msg" type="text" />
    <button onclick="sendMessage()">發(fā)送</button>

    <script>
        var ws = new WebSocket("ws://localhost:8080/ws");
        ws.onmessage = function(event) {
            var chatbox = document.getElementById('chatbox');
            chatbox.innerHTML += event.data + "<br/>";
        };

        function sendMessage() {
            var msg = document.getElementById("msg").value;
            ws.send(msg);
        }
    </script>
</body>
</html>

運(yùn)行 Go 服務(wù):

go run main.go

打開瀏覽器,訪問(wèn) index.html,即可體驗(yàn)多人聊天室的功能。

到此這篇關(guān)于使用Go語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單聊天系統(tǒng)的文章就介紹到這了,更多相關(guān)Go語(yǔ)言聊天系統(tǒng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • go語(yǔ)言區(qū)塊鏈實(shí)戰(zhàn)實(shí)現(xiàn)簡(jiǎn)單的區(qū)塊與區(qū)塊鏈

    go語(yǔ)言區(qū)塊鏈實(shí)戰(zhàn)實(shí)現(xiàn)簡(jiǎn)單的區(qū)塊與區(qū)塊鏈

    這篇文章主要為大家介紹了go語(yǔ)言區(qū)塊鏈的實(shí)戰(zhàn)學(xué)習(xí),來(lái)實(shí)現(xiàn)簡(jiǎn)單的區(qū)塊與區(qū)塊鏈?zhǔn)纠^(guò)程,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-10-10
  • Golang必知必會(huì)之Go?Mod命令詳解

    Golang必知必會(huì)之Go?Mod命令詳解

    go mod可以使項(xiàng)目從GOPATH的強(qiáng)制依賴中獨(dú)立出來(lái),也就是說(shuō)你的項(xiàng)目依賴不再需要放在在GOPATH下面了,下面這篇文章主要給大家介紹了關(guān)于Golang必知必會(huì)之Go?Mod命令的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07
  • golang?gin框架實(shí)現(xiàn)大文件的流式上傳功能

    golang?gin框架實(shí)現(xiàn)大文件的流式上傳功能

    這篇文章主要介紹了golang?gin框架中實(shí)現(xiàn)大文件的流式上傳,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • go語(yǔ)言實(shí)現(xiàn)接口查詢

    go語(yǔ)言實(shí)現(xiàn)接口查詢

    這篇文章主要介紹了go語(yǔ)言實(shí)現(xiàn)接口查詢,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • Go簡(jiǎn)單實(shí)現(xiàn)協(xié)程池的實(shí)現(xiàn)示例

    Go簡(jiǎn)單實(shí)現(xiàn)協(xié)程池的實(shí)現(xiàn)示例

    本文主要介紹了Go簡(jiǎn)單實(shí)現(xiàn)協(xié)程池的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Go語(yǔ)言高效編程的3個(gè)技巧總結(jié)

    Go語(yǔ)言高效編程的3個(gè)技巧總結(jié)

    Go語(yǔ)言是一種開源編程語(yǔ)言,可輕松構(gòu)建簡(jiǎn)單、可靠且高效的軟件,下面這篇文章主要給大家分享介紹了關(guān)于Go語(yǔ)言高效編程的3個(gè)技巧,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-01-01
  • golang與pgsql交互的實(shí)現(xiàn)

    golang與pgsql交互的實(shí)現(xiàn)

    本文主要介紹了golang與pgsql交互的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • Go語(yǔ)言中XML文件的讀寫操作

    Go語(yǔ)言中XML文件的讀寫操作

    本文主要介紹了Go語(yǔ)言中XML文件的讀寫操作,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • golang判斷兩個(gè)事件是否存在沖突的方法示例

    golang判斷兩個(gè)事件是否存在沖突的方法示例

    這篇文章主要為大家詳細(xì)介紹了golang判斷兩個(gè)事件是否存在沖突的方法示例,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-10-10
  • golang 跳出for循環(huán)操作

    golang 跳出for循環(huán)操作

    這篇文章主要介紹了golang 跳出for循環(huán)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12

最新評(píng)論