2024-04-02 18:24:46 +08:00
|
|
|
package tcp
|
|
|
|
|
|
|
|
import (
|
2024-04-13 09:40:25 +08:00
|
|
|
"context"
|
2024-04-02 18:24:46 +08:00
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"log/slog"
|
|
|
|
"net"
|
|
|
|
)
|
|
|
|
|
|
|
|
type TcpClient struct {
|
2024-06-12 19:50:36 +08:00
|
|
|
conn *net.TCPConn
|
|
|
|
handler func(n int, data []byte)
|
|
|
|
ctx context.CancelFunc
|
|
|
|
conning bool
|
2024-04-02 18:24:46 +08:00
|
|
|
}
|
|
|
|
|
2024-06-12 19:50:36 +08:00
|
|
|
func StartTcpClient(rAddr string, handler func(n int, data []byte), readErr func(err error)) (*TcpClient, error) {
|
2024-04-02 18:24:46 +08:00
|
|
|
raddr, addErr := net.ResolveTCPAddr("tcp", rAddr)
|
|
|
|
if addErr != nil {
|
|
|
|
return nil, addErr
|
|
|
|
}
|
|
|
|
conn, err := net.DialTCP("tcp", nil, raddr)
|
2024-04-13 09:40:25 +08:00
|
|
|
ctx, ctxFun := context.WithCancel(context.Background())
|
2024-06-13 10:06:54 +08:00
|
|
|
client := &TcpClient{conn: conn, ctx: ctxFun}
|
2024-04-02 18:24:46 +08:00
|
|
|
if err != nil {
|
2024-06-13 10:06:54 +08:00
|
|
|
client.ctx = ctxFun
|
|
|
|
client.conning = false
|
2024-04-02 18:24:46 +08:00
|
|
|
return nil, err
|
|
|
|
}
|
2024-06-13 10:06:54 +08:00
|
|
|
|
2024-04-02 18:24:46 +08:00
|
|
|
go func() {
|
|
|
|
for {
|
2024-04-13 09:40:25 +08:00
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
}
|
2024-04-02 18:24:46 +08:00
|
|
|
data := make([]byte, 1024)
|
2024-06-13 10:06:54 +08:00
|
|
|
l, readDataErr := conn.Read(data)
|
|
|
|
if readDataErr != nil {
|
|
|
|
if opErr, ok := readDataErr.(*net.OpError); ok {
|
2024-04-16 17:26:37 +08:00
|
|
|
slog.Error(fmt.Sprintf("TCP客户端[rAddr:%s]读取数据异常连接可能断开:", rAddr), opErr)
|
2024-05-24 09:00:43 +08:00
|
|
|
client.conning = false
|
2024-06-13 10:06:54 +08:00
|
|
|
readErr(readDataErr)
|
2024-06-13 11:10:42 +08:00
|
|
|
} else if readDataErr == io.EOF {
|
2024-04-02 18:24:46 +08:00
|
|
|
slog.Warn(fmt.Sprintf("TCP客户端[rAddr:%s]断开连接:", rAddr))
|
2024-05-24 09:00:43 +08:00
|
|
|
client.conning = false
|
2024-06-13 11:10:42 +08:00
|
|
|
readErr(readDataErr)
|
|
|
|
} else {
|
|
|
|
slog.Error(fmt.Sprintf("TCP客户端[rAddr:%s]读数据出错:%s", raddr, readDataErr))
|
|
|
|
client.conning = false
|
|
|
|
readErr(readDataErr)
|
2024-04-02 18:24:46 +08:00
|
|
|
}
|
2024-06-13 10:06:54 +08:00
|
|
|
return
|
2024-04-02 18:24:46 +08:00
|
|
|
}
|
2024-05-24 09:00:43 +08:00
|
|
|
client.conning = true
|
2024-06-12 19:50:36 +08:00
|
|
|
handler(l, data)
|
2024-04-02 18:24:46 +08:00
|
|
|
}
|
|
|
|
}()
|
2024-05-24 09:00:43 +08:00
|
|
|
client.conning = true
|
|
|
|
return client, nil
|
2024-04-02 18:24:46 +08:00
|
|
|
}
|
|
|
|
func (c *TcpClient) Close() {
|
2024-04-29 13:58:14 +08:00
|
|
|
if c != nil && c.conn != nil {
|
2024-04-13 09:40:25 +08:00
|
|
|
slog.Info(fmt.Sprintf("TCP客户端[rAddr:%s]关闭连接", c.conn.RemoteAddr().String()))
|
|
|
|
c.ctx()
|
2024-04-02 18:24:46 +08:00
|
|
|
c.conn.Close()
|
|
|
|
c.conn = nil
|
|
|
|
}
|
|
|
|
}
|
2024-05-24 09:00:43 +08:00
|
|
|
func (c *TcpClient) IsConning() bool {
|
|
|
|
if c != nil && c.conn != nil {
|
|
|
|
return c.conning
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2024-04-18 11:14:05 +08:00
|
|
|
func (c *TcpClient) Send(data []byte) error {
|
2024-04-18 11:18:26 +08:00
|
|
|
|
|
|
|
if c == nil || c.conn == nil {
|
2024-06-13 10:06:54 +08:00
|
|
|
//slog.Error("tcp client send error,conn is nil")
|
|
|
|
return fmt.Errorf("tcp client send error,conn is nil")
|
2024-04-16 17:26:37 +08:00
|
|
|
}
|
2024-04-02 18:24:46 +08:00
|
|
|
_, err := c.conn.Write(data)
|
|
|
|
if err != nil {
|
2024-06-13 10:06:54 +08:00
|
|
|
//slog.Error("tcp client send error", "error", err)
|
2024-04-18 11:14:05 +08:00
|
|
|
return err
|
2024-04-02 18:24:46 +08:00
|
|
|
}
|
2024-04-18 11:14:05 +08:00
|
|
|
return nil
|
2024-04-02 18:24:46 +08:00
|
|
|
}
|