You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

151 lines
2.6 KiB
Go

package client
import (
"net"
"sync"
"time"
"github.com/noahlann/nnet/pkg/client"
)
// udpClient UDP客户端实现
type udpClient struct {
config *client.Config
conn *net.UDPConn
serverAddr *net.UDPAddr
mu sync.RWMutex
connected bool
}
// NewUDPClient 创建UDP客户端
func NewUDPClient(config *client.Config) client.Client {
if config == nil {
config = client.DefaultConfig()
}
return &udpClient{
config: config,
connected: false,
}
}
// Connect 连接服务器
func (c *udpClient) Connect() error {
c.mu.Lock()
defer c.mu.Unlock()
if c.connected {
return nil
}
// 解析地址
addr := c.config.Addr
if len(addr) > 6 && addr[:6] == "udp://" {
addr = addr[6:]
}
// 解析服务器地址
serverAddr, err := net.ResolveUDPAddr("udp", addr)
if err != nil {
return client.NewErrorf("failed to resolve UDP address: %v", err)
}
// 创建UDP连接
conn, err := net.DialUDP("udp", nil, serverAddr)
if err != nil {
return client.NewErrorf("failed to dial UDP: %v", err)
}
c.conn = conn
c.serverAddr = serverAddr
c.connected = true
return nil
}
// Disconnect 断开连接
func (c *udpClient) Disconnect() error {
c.mu.Lock()
defer c.mu.Unlock()
if !c.connected {
return nil
}
if c.conn != nil {
c.conn.Close()
c.conn = nil
}
c.connected = false
return nil
}
// Send 发送数据
func (c *udpClient) Send(data []byte) error {
c.mu.RLock()
defer c.mu.RUnlock()
if !c.connected || c.conn == nil {
return client.NewError("not connected")
}
_, err := c.conn.Write(data)
return err
}
// Receive 接收数据
func (c *udpClient) Receive() ([]byte, error) {
c.mu.RLock()
defer c.mu.RUnlock()
if !c.connected || c.conn == nil {
return nil, client.NewError("not connected")
}
// 设置读取超时
if c.config.ReadTimeout > 0 {
c.conn.SetReadDeadline(time.Now().Add(c.config.ReadTimeout))
}
buffer := make([]byte, 4096)
n, err := c.conn.Read(buffer)
if err != nil {
return nil, err
}
result := make([]byte, n)
copy(result, buffer[:n])
return result, nil
}
// Request 请求-响应(带超时)
func (c *udpClient) Request(data []byte, timeout time.Duration) ([]byte, error) {
// 发送请求
if err := c.Send(data); err != nil {
return nil, err
}
// 设置读取超时
oldTimeout := c.config.ReadTimeout
c.config.ReadTimeout = timeout
defer func() {
c.config.ReadTimeout = oldTimeout
}()
// 接收响应
return c.Receive()
}
// IsConnected 检查是否已连接
func (c *udpClient) IsConnected() bool {
c.mu.RLock()
defer c.mu.RUnlock()
return c.connected
}
// Close 关闭客户端
func (c *udpClient) Close() error {
return c.Disconnect()
}