【问题标题】:Failure in creation of simple TCP server that accepts variable message lengths创建接受可变消息长度的简单 TCP 服务器失败
【发布时间】:2021-06-18 21:08:15
【问题描述】:

我正在尝试在 golang 中创建一个 tcp 服务器/客户端连接。我正在发送消息长度,因此服务器将接受多条消息,直到达到消息长度。当我尝试读取消息头以确定消息长度时,没有输出。当调用“conn.read(b)”时,代码似乎卡在了服务器的 tcpreader 函数的 for 循环中。什么可能导致此失败?

我的服务器代码:

package main

import (
        "bufio"
        "bytes"
        "encoding/binary"
        "fmt"
        "log"
        "net"
        "strings"
)

type hdr struct {
        magicNum uint64
        msgLen   uint32
        msgType  uint16
        padding  uint16
}

func tcpReader(conn net.Conn) {
        foundLength := false
        var hdr struct {
                magicNum uint64
                msgLen   uint32
                msgType  uint16
                padding  uint16
        }

        hdrSize := 16
        fmt.Println("tcpReader() header size %v", hdrSize)
        //localBuffer := new(bytes.Buffer)
        defer conn.Close()
        for {
                if !foundLength {
                        fmt.Println("tcpReader() Getting the lenght of the message")
                        var b = make([]byte, hdrSize)
                        // where the code seems to get stuck
                        read, err := conn.Read(b)
                        if err != nil {
                                fmt.Println("Failed to read header size %v", hdrSize)
                                fmt.Println(err)
                                continue
                        }
                        fmt.Println("tcpReader() read header bytes %v %v x", read, string(b))
                        if read != hdrSize { //add logic check magic number etc
                                fmt.Println("invalid header")
                                continue
                        }
                        err = binary.Read(bytes.NewReader(b[:16]), binary.BigEndian, &hdr)
                        if err != nil {
                                log.Fatal(err)
                        }
                        fmt.Println("tcpReader() read header bytes %v", hdr.msgLen)
                        foundLength = true
                        //                      messageLength = int(binary.BigEndian.Uint64(b))
                } else {
                        var message = make([]byte, hdr.msgLen)
                        read, err := conn.Read(message)
                        if err != nil {
                                fmt.Println(err)
                                continue
                        }
                        fmt.Println("Received bytes: %v", read)
                        if read != int(hdr.msgLen) {
                                //Add logic to append the read message and update the readSofarBytes etc
                                fmt.Println("invalid data")
                                continue
                        }
                        fmt.Println("Received:", string(message))
                        foundLength = false
                }
        }
}

func main() {
        fmt.Println("Launching server...")
        fmt.Println("Listen on port")
        /*      addr, err := net.ResolveTCPAddr("ip4", "127.0.0.1:8081")
                if err != nil {
                        panic(err)
                }*/
        ln, err := net.Listen("tcp", "127.0.0.1:8081")
        if err != nil {
                log.Fatal(err)
        }
        defer ln.Close()

        fmt.Println("Accept connection on port")
        for {
                conn, err := ln.Accept()
                if err != nil {
                        log.Fatal(err)
                }
                fmt.Println("Calling handleConnection")
                //go handleConnection(conn)
                go tcpReader(conn)
        }
}
   

我的客户代码:

package main

import (
        "bufio"
        "bytes"
        "encoding/binary"
        "fmt"
        "net"
)

type hdr struct {
        magicNum uint64
        msgLen   int
        msgType  uint16
        padding  uint16
        msg      string
}

func main() {
        var bin_buf bytes.Buffer
        msg := hdr{magicNum: 123456789,
                msgLen:  60,
                msgType: 2,
                padding: 0,
                msg:     "Hello world this is tcp message with big header"}
        msg.msgLen = int(len(msg.msg))
        fmt.Printf("message length %v\n", msg.msgLen)
        binary.Write(&bin_buf, binary.BigEndian, msg)
        addr, _ := net.ResolveTCPAddr("tcp", ":8081")
        conn, err := net.DialTCP("tcp", nil, addr)
        if err != nil {
                panic(err.Error())
        }
        //      conn.Write(bin_buf.Bytes())
        conn.Write(bin_buf.Bytes())
        //conn.Write([]byte("Hello from Clinet\n"))
        message, _ := bufio.NewReader(conn).ReadString('\n')
        fmt.Print(message)
        conn.Close()
}

                                                   

【问题讨论】:

    标签: go tcp network-programming


    【解决方案1】:

    这是因为您根本没有从客户端编写任何内容。你永远不应该忽略 golang 中的错误处理。更改这些行,你会看到错误在哪里:

        err := binary.Write(&bin_buf, binary.BigEndian, msg)
        if err != nil {
            panic(err.Error())
        }
    

    客户端正在向连接写入 0 个字节,因为没有任何字节

    panic: binary.Write: invalid type main.hdr
    

    【讨论】:

      【解决方案2】:

      要完成 Keser 的回答,您不能使用其字段的类型没有固定大小的结构。在这种情况下,您的 hdr 结构有两个字段无法使用 binary.Write 写入,message 字段类型为 string 和 msgLen,但未指定 int 大小。您将不得不手动编写字符串消息,因为它取决于开发人员在通过 TCP 连接编写字符串时如何处理字符串。此外,您的结构的所有字段都未导出,binary.Write 将无法访问它们。使用大写字母导出它们。

      【讨论】:

      • 你是对的,感谢您的贡献
      【解决方案3】:

      你试试就知道了。

      func main() {
          ...
          err := binary.Write(&bin_buf, binary.BigEndian, msg)
          fmt.Println(err)
          fmt.Println(string(bin_buf.Bytes()))
          ...
      }
      

      【讨论】:

        猜你喜欢
        • 2021-07-13
        • 1970-01-01
        • 2014-03-02
        • 2017-11-26
        • 2021-02-19
        • 1970-01-01
        • 2018-05-16
        • 2020-06-03
        • 2010-10-30
        相关资源
        最近更新 更多