Golang实现异步读写TCP服务器

Golang实现异步读写TCP服务器 你好,

我想创建一个能够接收和发送二进制数据的TCP服务器。我希望即使客户端不发送数据,也能向客户端发送数据。我已经尝试了一个使用Go协程来接收和发送数据的测试程序。当客户端断开连接时,一切正常。但当服务器尝试断开客户端连接时,有时会成功。

func main() {
    fmt.Println("hello world")
}
1 回复

更多关于Golang实现异步读写TCP服务器的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


以下是一个使用Go语言实现的异步读写TCP服务器示例,支持主动向客户端发送二进制数据:

package main

import (
    "fmt"
    "net"
    "sync"
    "time"
)

type Client struct {
    conn net.Conn
    send chan []byte
}

type Server struct {
    clients    map[*Client]bool
    register   chan *Client
    unregister chan *Client
    broadcast  chan []byte
    mutex      sync.RWMutex
}

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

func (s *Server) Run() {
    for {
        select {
        case client := <-s.register:
            s.mutex.Lock()
            s.clients[client] = true
            s.mutex.Unlock()
            fmt.Printf("客户端连接: %v\n", client.conn.RemoteAddr())
            
        case client := <-s.unregister:
            s.mutex.Lock()
            if _, ok := s.clients[client]; ok {
                close(client.send)
                client.conn.Close()
                delete(s.clients, client)
                fmt.Printf("客户端断开: %v\n", client.conn.RemoteAddr())
            }
            s.mutex.Unlock()
            
        case message := <-s.broadcast:
            s.mutex.RLock()
            for client := range s.clients {
                select {
                case client.send <- message:
                default:
                    close(client.send)
                    delete(s.clients, client)
                }
            }
            s.mutex.RUnlock()
        }
    }
}

func (s *Server) Start(addr string) error {
    listener, err := net.Listen("tcp", addr)
    if err != nil {
        return err
    }
    defer listener.Close()
    
    go s.Run()
    
    fmt.Printf("服务器监听: %s\n", addr)
    
    for {
        conn, err := listener.Accept()
        if err != nil {
            fmt.Printf("接受连接错误: %v\n", err)
            continue
        }
        
        client := &Client{
            conn: conn,
            send: make(chan []byte, 256),
        }
        
        s.register <- client
        
        go s.handleRead(client)
        go s.handleWrite(client)
    }
}

func (s *Server) handleRead(client *Client) {
    defer func() {
        s.unregister <- client
    }()
    
    buffer := make([]byte, 4096)
    for {
        n, err := client.conn.Read(buffer)
        if err != nil {
            return
        }
        
        data := buffer[:n]
        fmt.Printf("收到来自 %v 的数据: %v\n", client.conn.RemoteAddr(), data)
        
        // 示例:将接收到的数据广播给所有客户端
        s.broadcast <- data
    }
}

func (s *Server) handleWrite(client *Client) {
    defer func() {
        s.unregister <- client
    }()
    
    for {
        select {
        case message, ok := <-client.send:
            if !ok {
                return
            }
            
            _, err := client.conn.Write(message)
            if err != nil {
                return
            }
            fmt.Printf("发送数据到 %v: %v\n", client.conn.RemoteAddr(), message)
        }
    }
}

// 示例:主动向所有客户端发送数据
func (s *Server) SendToAll(data []byte) {
    s.broadcast <- data
}

// 示例:定时发送心跳包
func (s *Server) StartHeartbeat(interval time.Duration) {
    go func() {
        ticker := time.NewTicker(interval)
        defer ticker.Stop()
        
        for range ticker.C {
            heartbeat := []byte{0x01, 0x02, 0x03, 0x04} // 示例心跳数据
            s.SendToAll(heartbeat)
        }
    }()
}

func main() {
    server := NewServer()
    
    // 启动心跳机制(每5秒发送一次)
    server.StartHeartbeat(5 * time.Second)
    
    // 启动服务器
    err := server.Start(":8080")
    if err != nil {
        fmt.Printf("服务器启动失败: %v\n", err)
    }
}

这个实现包含以下关键特性:

  1. 异步读写分离:每个客户端连接使用独立的goroutine处理读和写操作
  2. 主动发送能力:通过SendToAll方法可以随时向所有客户端发送二进制数据
  3. 连接管理:使用注册/注销机制管理客户端连接
  4. 线程安全:使用读写锁保护共享数据
  5. 心跳机制:示例展示了如何定时向客户端发送数据

服务器断开客户端连接的逻辑在unregister通道处理中,确保连接正确关闭和资源释放。

回到顶部