91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

golang用TCP協議實現簡單的聊天室

發布時間:2020-10-01 06:35:31 來源:網絡 閱讀:37634 作者:ustb80 欄目:編程語言

通常聊天室的架構分為服務器端和客戶端:

服務器端:
接受來自于客戶端的連接請求并建立連接;
所有客戶端的連接會放進連接池中,用于廣播消息;

客戶端:
連接服務器;
向服務器發送消息;
接收服務器的廣播消息;

注意事項:
某一個客戶端斷開連接后需要從連接池中摘除,并不再接收廣播消息;
某一個客戶端斷開連接后不能影響服務器端或別的客戶端的連接;

詳細的代碼如下,文檔看注釋就好了,不再細說:

服務器:

server.go

package main

import (
    "net"
    "log"
    "fmt"
)

func main() {
    port := "9090"
    Start(port)
}

// 啟動服務器
func Start(port string) {
    host := ":" + port

    // 獲取tcp地址
    tcpAddr, err := net.ResolveTCPAddr("tcp4", host)
    if err != nil {
        log.Printf("resolve tcp addr failed: %v\n", err)
        return
    }

    // 監聽
    listener, err := net.ListenTCP("tcp", tcpAddr)
    if err != nil {
        log.Printf("listen tcp port failed: %v\n", err)
        return
    }

    // 建立連接池,用于廣播消息
    conns := make(map[string]net.Conn)

    // 消息通道
    messageChan := make(chan string, 10)

    // 廣播消息
    go BroadMessages(&conns, messageChan)

    // 啟動
    for {
        fmt.Printf("listening port %s ...\n", port)
        conn, err := listener.AcceptTCP()
        if err != nil {
            log.Printf("Accept failed:%v\n", err)
            continue
        }

        // 把每個客戶端連接扔進連接池
        conns[conn.RemoteAddr().String()] = conn
        fmt.Println(conns)

        // 處理消息
        go Handler(conn, &conns, messageChan)
    }
}

// 向所有連接上的鄉親們發廣播
func BroadMessages(conns *map[string]net.Conn, messages chan string) {
    for {

        // 不斷從通道里讀取消息
        msg := <-messages
        fmt.Println(msg)

        // 向所有的鄉親們發消息
        for key, conn := range *conns {
            fmt.Println("connection is connected from ", key)
            _, err := conn.Write([]byte(msg))
            if err != nil {
                log.Printf("broad message to %s failed: %v\n", key, err)
                delete(*conns, key)
            }
        }
    }
}

// 處理客戶端發到服務端的消息,將其扔到通道中
func Handler(conn net.Conn, conns *map[string]net.Conn, messages chan string) {
    fmt.Println("connect from client ", conn.RemoteAddr().String())

    buf := make([]byte, 1024)
    for {
        length, err := conn.Read(buf)
        if err != nil {
            log.Printf("read client message failed:%v\n", err)
            delete(*conns, conn.RemoteAddr().String())
            conn.Close()
            break
        }

        // 把收到的消息寫到通道中
        recvStr := string(buf[0:length])
        messages <- recvStr
    }
}

客戶端:
client.go

package main

import (
    "net"
    "log"
    "fmt"
    "os"
)

func main() {
    Start(os.Args[1])
}

func Start(tcpAddrStr string) {
    tcpAddr, err := net.ResolveTCPAddr("tcp4", tcpAddrStr)
    if err != nil {
        log.Printf("Resolve tcp addr failed: %v\n", err)
        return
    }

    // 向服務器撥號
    conn, err := net.DialTCP("tcp", nil, tcpAddr)
    if err != nil {
        log.Printf("Dial to server failed: %v\n", err)
        return
    }

    // 向服務器發消息
    go SendMsg(conn)

    // 接收來自服務器端的廣播消息
    buf := make([]byte, 1024)
    for {
        length, err := conn.Read(buf)
        if err != nil {
            log.Printf("recv server msg failed: %v\n", err)
            conn.Close()
            os.Exit(0)
            break
        }

        fmt.Println(string(buf[0:length]))
    }
}

// 向服務器端發消息
func SendMsg(conn net.Conn) {
    username := conn.LocalAddr().String()
    for {
        var input string

        // 接收輸入消息,放到input變量中
        fmt.Scanln(&input)

        if input == "/q" || input == "/quit" {
            fmt.Println("Byebye ...")
            conn.Close()
            os.Exit(0)
        }

        // 只處理有內容的消息
        if len(input) > 0 {
            msg := username + " say:" + input
            _, err := conn.Write([]byte(msg))
            if err != nil {
                conn.Close()
                break
            }
        }
    }
}

測試方法:

編譯server.go和client.go;
打開終端,啟動server,默認會監聽9090端口;
再打開多個終端,啟動client,client啟動命令:client 服務器IP:9090;
在client中輸入字符并回車,可以看到別的終端都會收到消息;

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

塔河县| 博爱县| 扬州市| 会泽县| 铜川市| 墨玉县| 宁国市| 延川县| 应城市| 金平| 常宁市| 金秀| 杨浦区| 民乐县| 抚顺县| 罗平县| 尼勒克县| 隆德县| 永济市| 睢宁县| 峡江县| 固始县| 陆川县| 南雄市| 镇巴县| 三都| 晋州市| 邢台县| 师宗县| 平乐县| 昆山市| 玛纳斯县| 衡水市| 思茅市| 桐城市| 托克逊县| 武隆县| 阜新市| 隆子县| 长泰县| 定西市|