1、IM:基础连接

IM:基础连接

1、服务端

go 复制代码
// server.go
package main

import (
    "bufio"
    "fmt"
    "net"
    "strings"
    "sync"
)

var (
    clients = make(map[net.Conn]string)
    mu      sync.Mutex
)

func broadcast(msg string, sender net.Conn) {
    mu.Lock()
    defer mu.Unlock()

    for conn := range clients {
        if conn != sender {
            fmt.Fprintln(conn, msg)
        }
    }
}

func handleClient(conn net.Conn) {
    defer conn.Close()

    // 读取用户名(第一行)
    reader := bufio.NewReader(conn)
    username, err := reader.ReadString('\n')
    if err != nil {
        fmt.Println("Error reading username:", err)
        return
    }
    username = strings.TrimSpace(username)
    if username == "" {
        username = "Anonymous"
    }

    mu.Lock()
    clients[conn] = username
    mu.Unlock()

    fmt.Printf("User %s joined.\n", username)
    broadcast(fmt.Sprintf("[Server] %s joined the chat.", username), conn)

    // 广播消息循环
    for {
        msg, err := reader.ReadString('\n')
        if err != nil {
            break
        }
        msg = strings.TrimSpace(msg)
        if msg == "" {
            continue
        }
        fullMsg := fmt.Sprintf("[%s] %s", username, msg)
        fmt.Println(fullMsg) // 服务端日志
        broadcast(fullMsg, conn)
    }

    // 用户断开
    mu.Lock()
    delete(clients, conn)
    mu.Unlock()
    broadcast(fmt.Sprintf("[Server] %s left the chat.", username), nil)
    fmt.Printf("User %s disconnected.\n", username)
}

func main() {
    listener, err := net.Listen("tcp", ":8080")
    if err != nil {
        panic(err)
    }
    defer listener.Close()

    fmt.Println("IM Server started on :8080")

    for {
        conn, err := listener.Accept()
        if err != nil {
            fmt.Println("Accept error:", err)
            continue
        }
        go handleClient(conn)
    }
}

2、客户端

go 复制代码
// client.go
package main

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

func main() {
    conn, err := net.Dial("tcp", "localhost:8080")
    if err != nil {
        panic(err)
    }
    defer conn.Close()

    fmt.Print("Enter your username: ")
    reader := bufio.NewReader(os.Stdin)
    username, _ := reader.ReadString('\n')
    username = strings.TrimSpace(username)

    // 发送用户名
    fmt.Fprintln(conn, username)

    // 启动 goroutine 接收消息
    go func() {
        in := bufio.NewScanner(conn)
        for in.Scan() {
            fmt.Println(in.Text())
        }
    }()

    // 主线程发送消息
    for {
        fmt.Print("> ")
        msg, _ := reader.ReadString('\n')
        msg = strings.TrimSpace(msg)
        if msg == "/quit" {
            break
        }
        fmt.Fprintln(conn, msg)
    }
}
相关推荐
AiMan4 分钟前
别再把秘塔会话逐个点开:这可把秘塔多个会话一次导出?AI导出鸭
前端·后端·面试
nice_lcj5201 小时前
【从零理解 Spring AI · 12】MCP 的两种角色:做客户端还是做服务端
java·后端·spring·spring ai·ai应用开发
卷无止境1 小时前
mathmodel-figure-templates 以及两个上手案例
后端·python
Moment1 小时前
写给迷茫的应届生,怎样在 AI 时代争取更多机会
前端·后端·面试
回家路上绕了弯1 小时前
为什么还是不能直接把需求丢给 AI?
后端
fengci.1 小时前
CTF2MISC中等部分
开发语言·前端·学习
锋行天下2 小时前
服务器 Python 2.7 装不了 langgraph-cli?用本地生成 Dockerfile 曲线救国
人工智能·后端·python
桦说编程2 小时前
TransmittableThreadLocal 解读:从 CRR 机制到上下文所有权
java·后端·源码
喵个咪2 小时前
GoWind 拆解:全链 ID 类型体系——int64 定版与前端字符串化契约
前端·后端·go
xys_6782 小时前
JavaEE通关手册:初识Java
java·开发语言