|
@@ -9,6 +9,7 @@ import (
|
|
|
"path/filepath"
|
|
|
"server/dao"
|
|
|
"server/logger"
|
|
|
+ "strings"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
@@ -156,8 +157,9 @@ func SaveData(path string, parameter interface{}) error {
|
|
|
}
|
|
|
|
|
|
const (
|
|
|
- maxRetries = 3 // 最大重试次数
|
|
|
- writeTimeout = 5 * time.Second // 写入超时时间
|
|
|
+ maxRetries = 3 // 最大重试次数
|
|
|
+ writeTimeout = 5 * time.Second // 写入超时时间
|
|
|
+ reconnectWait = 2 * time.Second // 重连等待时间
|
|
|
)
|
|
|
|
|
|
func WriteDevice(frame []byte, conn net.Conn) error {
|
|
@@ -169,13 +171,12 @@ func WriteDevice(frame []byte, conn net.Conn) error {
|
|
|
|
|
|
_, err := conn.Write(frame)
|
|
|
if err == nil {
|
|
|
- logger.Get().Infof("Successfully wrote frame to device")
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
- // 检查是否是 broken pipe 或 connection reset by peer 错误
|
|
|
- if ne, ok := err.(*net.OpError); ok && (ne.Err.Error() == "broken pipe" || ne.Err.Error() == "connection reset by peer") {
|
|
|
- logger.Get().Warnf("Connection closed by peer or broken pipe, retrying (%d/%d)", attempts+1, maxRetries)
|
|
|
+ // 检查是否是对端强制关闭连接的错误
|
|
|
+ if ne, ok := err.(*net.OpError); ok && (strings.Contains(ne.Err.Error(), "forcibly closed") || strings.Contains(ne.Err.Error(), "broken pipe") || strings.Contains(ne.Err.Error(), "connection reset")) {
|
|
|
+ logger.Get().Warnf("Connection forcibly closed by peer, retrying (%d/%d)", attempts+1, maxRetries)
|
|
|
|
|
|
// 关闭旧连接
|
|
|
if err := conn.Close(); err != nil {
|
|
@@ -184,16 +185,26 @@ func WriteDevice(frame []byte, conn net.Conn) error {
|
|
|
|
|
|
// 尝试重新建立连接
|
|
|
var newConn net.Conn
|
|
|
- newConn, err = net.Dial("tcp", conn.RemoteAddr().String())
|
|
|
+ remoteAddr := conn.RemoteAddr().String()
|
|
|
+
|
|
|
+ // 解析原始连接的远程地址和网络接口
|
|
|
+ addr, networkInterface, err := parseRemoteAddr(remoteAddr)
|
|
|
if err != nil {
|
|
|
- logger.Get().Errorf("Reconnect failed: %v", err)
|
|
|
+ logger.Get().Errorf("Failed to parse remote address: %v", err)
|
|
|
continue // 继续下一次重试
|
|
|
}
|
|
|
+
|
|
|
+ newConn, err = net.Dial("tcp", fmt.Sprintf("%s%%%s", addr, networkInterface))
|
|
|
+ if err != nil {
|
|
|
+ logger.Get().Errorf("Reconnect failed: %v", err)
|
|
|
+ time.Sleep(reconnectWait) // 等待一段时间后重试
|
|
|
+ continue // 继续下一次重试
|
|
|
+ }
|
|
|
conn = newConn
|
|
|
continue // 重试写入
|
|
|
}
|
|
|
|
|
|
- // 如果不是 broken pipe 或 connection reset by peer,则直接返回错误
|
|
|
+ // 如果不是对端强制关闭连接的错误,则直接返回错误
|
|
|
logger.Get().Errorf("Write failed: %v", err)
|
|
|
return fmt.Errorf("write failed after %d retries: %v", attempts+1, err)
|
|
|
}
|
|
@@ -201,6 +212,15 @@ func WriteDevice(frame []byte, conn net.Conn) error {
|
|
|
return fmt.Errorf("failed to write after %d retries", maxRetries)
|
|
|
}
|
|
|
|
|
|
+// 解析远程地址,提取 IP 地址和网络接口名称
|
|
|
+func parseRemoteAddr(addr string) (string, string, error) {
|
|
|
+ parts := strings.Split(addr, "%")
|
|
|
+ if len(parts) != 2 {
|
|
|
+ return "", "", fmt.Errorf("invalid remote address format: %s", addr)
|
|
|
+ }
|
|
|
+ return parts[0], parts[1], nil
|
|
|
+}
|
|
|
+
|
|
|
func WriteAndReadDevice(frame []byte, conn net.Conn, former, after int) (data []byte, err error) {
|
|
|
// 发送 Modbus RTU 帧
|
|
|
n, err := conn.Write(frame)
|