MENU

Go 学习笔记:基于net库实现的聊天室

September 12, 2021 • Read: 219 • Golang

Go 语言的net库真是太顶了!

今天在看go的net来着,就想顺手实现一个tcp聊天室,大致看了一下net这个库,发现它实现一个简易的tcp聊天室比使用C语言之流要简单的多

要想实现一个多人的聊天室,就得先弄明白单个客户端与服务端是如何交互的,这里我们先不使用协程来处理最简单的情况

服务端

/*
 * @Author: NorthCityChen
 * @LastEditTime: 2021-09-12 18:55:57
 * @Description:
 * @Website: https://grimoire.cn
 * Copyright (c) NorthCityChen All rights reserved.
 */
package main

import (
    "fmt"
    "net"
)

func main() {
    listener, err := net.Listen("tcp", ":3000")
    // Start listening
    if err != nil {
        fmt.Println(err)
        return
    }
    conn, err := listener.Accept()
    // Waiting for the client to connect (blocking)
    if err != nil {
        fmt.Println(err)
        return
    }
    for {
        buf := make([]byte, 512)
        length, err := conn.Read(buf)
        // conn.read(buf) 会将从conn传来的数据传到buf数组中
        if err != nil {
            fmt.Println(err)
            return
        }
        fmt.Println(length, string(buf))
        // 将buf中的数据打印出来
        if string(buf[:length]) == "end" {
            break
        }
        // 似乎这里会传过来一个换行符号,需要手动给他截掉
    }
    err = conn.Close()
    // 关闭链接 释放资源
    if err != nil {
        fmt.Println(err)
        return
    }
}

客户端

/*
 * @Author: NorthCityChen
 * @LastEditTime: 2021-09-12 18:36:35
 * @Description:
 * @Website: https://grimoire.cn
 * Copyright (c) NorthCityChen All rights reserved.
 */
package main

import (
    "fmt"
    "net"
)

func main() {
    client, err := net.Dial("tcp", "localhost:3000")
    // 启动客户端并连接服务端
    if err != nil {
        fmt.Println(err)
        return
    }
    defer client.Close()
    client.Write([]byte("Hello world"))
    // 将数据写入连接(传到服务端)
    if err != nil {
        fmt.Println(err)
    }
}

根据上述的原理,我们可以尝试写一个支持多客户端的聊天室(代码有点简陋,若有纰漏之处还请不吝赐教)

服务端

/*
 * @Author: NorthCityChen
 * @LastEditTime: 2021-09-12 20:21:22
 * @Description:
 * @Website: https://grimoire.cn
 * Copyright (c) NorthCityChen All rights reserved.
 */
package main

import (
    "fmt"
    "net"
)

var clients = make(map[net.Conn]bool)
var messages = make(chan []byte)

func main() {
    listener, err := net.Listen("tcp", ":8080")
    if err != nil {
        fmt.Println(err)
        return
    }
    go boardcast()
    for {
        conn, err := listener.Accept()
        if err != nil {
            fmt.Println(err)
            continue
        }
        go handleConnection(conn)
    }
}

// 全局广播
func boardcast() {
    for msg := range messages {
        for conn, _ := range clients {
            if _, err := conn.Write(msg); err != nil {
                fmt.Println(err)
                continue
            }
        }
        fmt.Println(msg)
    }
}

func handleConnection(conn net.Conn) {
    clients[conn] = true
    fmt.Println("[System]:", conn.RemoteAddr().String(), "进入聊天室")
    for {
        buf := make([]byte, 512)
        length, err := conn.Read(buf)
        if err != nil {
            fmt.Println(err)
            break
        }
        messages <- buf[:length]
    }

    delete(clients, conn)
    fmt.Println("[System]:", conn.RemoteAddr().String(), "离去...")
    conn.Close()
}

客户端

/*
 * @Author: NorthCityChen
 * @LastEditTime: 2021-09-12 20:14:09
 * @Description:
 * @Website: https://grimoire.cn
 * Copyright (c) NorthCityChen All rights reserved.
 */
package main

import (
    "bufio"
    "fmt"
    "net"
    "os"
)

func main() {
    client, err := net.Dial("tcp", "localhost:8080")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer client.Close()
    go func() {
        input := bufio.NewScanner(os.Stdin)
        for input.Scan() {
            client.Write(input.Bytes())
        }
    }()

    for {
        buf := make([]byte, 512)
        length, err := client.Read(buf)
        if err != nil {
            fmt.Println(err)
        }
        fmt.Println(string(buf[:length]))
    }
}
Archives Tip
QR Code for this page
Tipping QR Code