1. 程式人生 > >一對一聊天(有bug)

一對一聊天(有bug)

錯誤 其中 用戶id msg pack tro conn pri 聊天

此處固定是發給clients["1"]客戶端消息,也就是發給自己。而且不是線程安全的!!!

package main

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

type Message struct {
    Msg string // 消息內容
    ToId string // 目標用戶的id
    FromId string // 發送消息的用戶的id
}

var clients = make(map[string] *websocket.Conn) //連接客戶端(在線的),其中map的鍵為用戶id
var pushMsgs = make(chan Message, 1000) //要推送的消息

// 配置upgrader
var upgrader = websocket.Upgrader{
    // 允許跨域
    CheckOrigin: func(r *http.Request) bool {
        return true
    },
}

func main() {
    // 創建一個簡單的文件服務器
    fs := http.FileServer(http.Dir("../public"))
    http.Handle("/", fs)

    // 配置websocket路由
    http.HandleFunc("/ws", WsConns)

    // 收聽傳入的聊天信息
    go ToMessage()

    // 在本地主機端口上啟動並記錄所有錯誤
    log.Println("http server started on :8000")
    err := http.ListenAndServe(":8000", nil)
    if err != nil {
        log.Fatal("ListenAndServe error:", err)
    }
}

func WsConns(w http.ResponseWriter, r *http.Request) {
    //完成握手升級
    ws, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Fatal(err)
    }

    // 確保在函數返回時關閉連接
    defer ws.Close()

    // 提示下機
    defer fmt.Printf("——%v下機了——\n", ws.RemoteAddr())

    // 註冊新客戶端
    clients["1"] = ws

    //fmt.Println(clients["1"].)

    // 輸出ip
    fmt.Println("當前登錄用戶:", ws.RemoteAddr())

    for {
        var msg Message
        err := ws.ReadJSON(&msg)

        if err != nil {
            log.Printf("error1: %v", err)
            // 若接收消息錯誤,則將該發送消息的用戶的websocket連接去掉
            delete(clients, msg.FromId)
        }

        //將接收到的消息寫入消息channel
        pushMsgs <- msg
    }
}

func ToMessage() {
    for {
        // 從消息推送channel獲取消息
        msg := <- pushMsgs

        // 發送給指定的客戶端
        err := clients["1"].WriteJSON(msg)
        if err != nil {
            log.Printf("error2: %v", err)
            clients["1"].Close()
            delete(clients, "1")
        }

    }
}

一對一聊天(有bug)