Golang TCP服务器未返回预期响应如何解决

Golang TCP服务器未返回预期响应如何解决 我编写了两个程序,一个使用GO语言,另一个使用C#。我已经与一个服务器/设备建立了TCP连接。目前遇到两个问题:

当我从C#发送负载时,确实能收到响应,但在GO中却无法获得正确的响应。同样地,我在Wireshark中查看了数据包,它们是完全相同的。
此外,当我通过C#发送数据时,服务器会自动返回响应。然而,在GO中,我必须主动读取服务器/设备才能接收到数据。
3 回复

谢谢,我已经解决了这个问题。这与通道有关,我没有完美地配置我的接收器(这里指的是我的缓冲区)。

更多关于Golang TCP服务器未返回预期响应如何解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


仅从你的描述中,我无法理解实际发生了什么以及应该发生什么。

似乎有东西发送了请求并收到了响应,但这个请求从未到达另一个东西,所以它从未发送过响应?

  • 你有一些代码可以分享吗?
  • 你能使用 netcat 模拟出正确的行为吗?
  • 它们运行在同一个物理主机上吗?不同的主机?Docker?虚拟机?还是其他抽象或虚拟化了相关硬件的层?

在Go中处理TCP连接时,需要特别注意连接设置和读写方式。以下是常见问题和解决方案:

1. 连接设置问题 确保Go的TCP连接设置与C#一致,特别是SetNoDelaySetKeepAlive

conn, err := net.Dial("tcp", "server:port")
if err != nil {
    log.Fatal(err)
}
defer conn.Close()

// 重要设置
tcpConn := conn.(*net.TCPConn)
tcpConn.SetNoDelay(true)      // 禁用Nagle算法
tcpConn.SetKeepAlive(true)    // 启用保活机制
tcpConn.SetKeepAlivePeriod(30 * time.Second)

2. 读写时序问题 Go的读写需要精确控制,特别是读取时机:

// 发送数据
data := []byte("your payload")
n, err := conn.Write(data)
if err != nil {
    log.Printf("Write failed: %v", err)
    return
}
log.Printf("Sent %d bytes", n)

// 立即读取响应(根据协议调整)
buf := make([]byte, 1024)
conn.SetReadDeadline(time.Now().Add(5 * time.Second)) // 设置读取超时
n, err = conn.Read(buf)
if err != nil {
    log.Printf("Read failed: %v", err)
    return
}
log.Printf("Received %d bytes: %x", n, buf[:n])

3. 完整示例 这是一个完整的TCP客户端示例:

package main

import (
    "fmt"
    "log"
    "net"
    "time"
)

func main() {
    conn, err := net.Dial("tcp", "192.168.1.100:8080")
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()
    
    // 连接设置
    tcpConn := conn.(*net.TCPConn)
    tcpConn.SetNoDelay(true)
    tcpConn.SetKeepAlive(true)
    tcpConn.SetKeepAlivePeriod(30 * time.Second)
    
    // 发送数据
    message := []byte{0x01, 0x02, 0x03, 0x04} // 示例数据
    if _, err := conn.Write(message); err != nil {
        log.Fatal("Write error:", err)
    }
    fmt.Printf("Sent: %x\n", message)
    
    // 读取响应
    response := make([]byte, 4096)
    conn.SetReadDeadline(time.Now().Add(3 * time.Second))
    
    n, err := conn.Read(response)
    if err != nil {
        log.Fatal("Read error:", err)
    }
    
    fmt.Printf("Received %d bytes: %x\n", n, response[:n])
}

4. 调试建议 添加详细的日志记录来跟踪数据流:

// 记录发送和接收的原始数据
func debugHex(data []byte, prefix string) {
    fmt.Printf("%s: ", prefix)
    for _, b := range data {
        fmt.Printf("%02x ", b)
    }
    fmt.Println()
}

// 在Write和Read后调用
debugHex(message, "Sending")
debugHex(response[:n], "Received")

5. 协议处理 如果服务器使用特定协议,可能需要处理消息边界:

// 读取直到特定分隔符
func readUntil(conn net.Conn, delimiter byte) ([]byte, error) {
    var buf []byte
    temp := make([]byte, 1)
    
    for {
        _, err := conn.Read(temp)
        if err != nil {
            return nil, err
        }
        
        buf = append(buf, temp[0])
        if temp[0] == delimiter {
            break
        }
    }
    return buf, nil
}

主要差异通常在于:

  1. Go默认启用Nagle算法,可能需要显式禁用
  2. 读取时机和超时设置
  3. 缓冲区管理和消息边界处理

检查Wireshark确认数据包完全一致后,重点应放在连接设置和读写时序上。

回到顶部