| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 | package modbusimport (	"context"	"io"	"net"	"sync"	"time"	"golib/v3/gnet"	"golib/v3/log")// Conn PLC 主控连接type Conn interface {	// Connection 连接状态	gnet.Connection	// IsLocked 表示当前有其他线程正在与 PLC 交互	IsLocked() bool	// WriteResponse 向 PLC 发送数据并等待 PLC 响应	WriteResponse(b []byte) ([]byte, error)	// Closer 关闭与 PLC 主控的连接	io.Closer}const (	MaxReadBuffSize = 1024)type Dialer struct {	conn   net.Conn	buf    []byte	logger log.Logger	mu     sync.Mutex	lock   bool}func (w *Dialer) IsConnected() bool {	if w.conn == nil {		return false	}	return w.conn.(gnet.Connection).IsConnected()}func (w *Dialer) IsClosed() bool {	if w.conn == nil {		return true	}	return w.conn.(gnet.Connection).IsClosed()}func (w *Dialer) Reconnecting() bool {	if w.conn == nil {		return false	}	return w.conn.(gnet.Connection).Reconnecting()}func (w *Dialer) IsLocked() bool {	return w.lock}// WriteResponse 写入并读取下一次的数据func (w *Dialer) WriteResponse(b []byte) ([]byte, error) {	if w.conn == nil {		return nil, gnet.ErrConnNotFound	}	w.mu.Lock()	defer w.mu.Unlock()	w.lock = true	defer func() {		w.lock = false	}()	w.logger.Debug("WriteResponse: Write: %s", gnet.Bytes(b).HexTo())	if i, err := w.conn.Write(b); err != nil {		w.logger.Error("WriteResponse: Write err: %d->%d %s", len(b), i, err)		return nil, err	}	clear(w.buf)	n, err := w.conn.Read(w.buf)	if err != nil {		w.logger.Error("WriteResponse: Read err: %s", err)		return nil, err	}	w.logger.Debug("WriteResponse: Read: %s", gnet.Bytes(w.buf[:n]).HexTo())	return w.buf[:n], nil}func (w *Dialer) Close() error {	if w.conn == nil {		return nil	}	return w.conn.Close()}func (w *Dialer) DialContext(ctx context.Context, address string, logger log.Logger) (Conn, error) {	// 由于现场网络环境比较差, 因此加大超时时间以防止频繁掉线重连	cfg := &gnet.Config{		Timeout:     7 * time.Second,		DialTimeout: 10 * time.Second, // 提升机内部处理是 3s		Reconnect:   true,	}	if err := ctx.Err(); err != nil {		logger.Error("DialContext: %s", err)		return nil, err	}	if conn, err := gnet.DialTCPConfig(address, cfg); err == nil {		w.conn = conn	} else {		logger.Error("DialContext: %s", err)		return nil, err	}	go func() {		<-ctx.Done()		_ = w.conn.Close()		logger.Error("DialContext: %s", ctx.Err())	}()	w.buf = make([]byte, MaxReadBuffSize)	host, _, _ := net.SplitHostPort(address)	w.logger = log.Part(logger, "conn", host)	return w, nil}
 |