Proper way to send an int64 over a socket in go

huangapple go评论85阅读模式
英文:

Proper way to send an int64 over a socket in go

问题

我正在尝试在Golang中通过TCP发送int64类型的数据,但是接收方打印出来的数字与我发送的数字不同。请问正确的方法是什么?

// 客户端和服务器都需要使用缓冲区
buffer := make([]byte, 1024)

// 发送方
fileInfo, error := os.Stat(fileName)
if error != nil {
    fmt.Println("打开文件时出错")
}
var fSize int = int(fileInfo.Size())

connection.Write([]byte(string(fSize)))


// 接收方
connection.Read(buffer)

fileSize := new(big.Int).SetBytes(bytes.Trim(buffer, "\x00")).Int64()
if err != nil {
    fmt.Println("无效的文件大小")
    fileSize = 0
}

以上是你要翻译的内容。

英文:

I'm trying to send a int64 over a TCP in golang, however, my receiver prints gets a different number then what I've sent out. What is the proper way to accomplish this?

//Buffer on both client and server
buffer := make([]byte, 1024)

//Sender
fileInfo, error := os.Stat(fileName)
if error != nil {
	fmt.Println("Error opening file")
}
var fSize int = int(fileInfo.Size())

connection.Write([]byte(string(fSize)))


//Receiver
connection.Read(buffer)

fileSize := new(big.Int).SetBytes(bytes.Trim(buffer, "\x00")).Int64()
if err != nil {
    fmt.Println("not a valid filesize")
	fileSize = 0
}

答案1

得分: 7

使用binary.Write / binary.Read

//发送方
err := binary.Write(connection, binary.LittleEndian, fileInfo.Size())
if err != nil {
fmt.Println("err:", err)
}

//接收方
var size int64
err := binary.Read(connection, binary.LittleEndian, &size)
if err != nil {
fmt.Println("err:", err)
}

[]byte(string(fSize))并不会像你想的那样工作,它将数字视为Unicode字符,而不是返回其字符串表示形式。

如果你想要一个数字的字符串表示形式,请使用strconv.Itoa,如果你想要二进制表示形式,请使用:

num := make([]byte, 8) // 或者对于int32使用4,对于int16使用2
binary.LittleEndian.PutUint64(num, 1<<64-1)

英文:

Using binary.Write / binary.Read:

//sender
err := binary.Write(connection, binary.LittleEndian, fileInfo.Size())
if err != nil {
	fmt.Println(&quot;err:&quot;, err)
}

//receiver
var size int64
err := binary.Read(connection, binary.LittleEndian, &amp;size)
if err != nil {
	fmt.Println(&quot;err:&quot;, err)
}

[]byte(string(fSize)) doesn't do what you think it does, it treats the number as unicode character, it doesn't return the string representation of it.

If you want the string representation of a number, use strconv.Itoa, if you want the binary represention then use:

num := make([]byte, 8) // or 4 for int32 or 2 for int16
binary.LittleEndian.PutUint64(num, 1&lt;&lt;64-1) 

答案2

得分: 1

使用binary.BigEndianbinary.LittleEndian来编码整数:

var size int64

// 发送
var buf [8]byte
binary.BigEndian.PutUint64(buf[:], uint64(size))
_, err := w.Write(buf[:])

// 接收
var buf [8]byte
_, err := io.ReadFull(r, buf[:])
if err != nil {
    // 处理错误
}
size = int64(binary.BigEndian.Uint64(buf[:]))

你也可以使用binary.Readbinary.Write。这样做会使你的应用代码稍微变短,但需要在这些函数内部进行类型转换和其他操作。

关于问题中的代码,有几点需要注意:

string(fSize)将返回rune fSize的UTF-8表示形式。它不会返回十进制编码或二进制编码的值。使用strconv包将数值转换为十进制表示形式。使用上述提到的binary包将其转换为二进制表示形式。

以下代码片段:

connection.Read(buffer)
buffer = bytes.Trim(buffer, "\x00")

如果数据包含在末尾有一个0字节的情况下,会删除真实数据。Read函数返回读取的字节数。使用该长度来切片缓冲区:

n, err := connection.Read(buffer)
buffer = buffer[:n]
英文:

Use binary.BigEndian or binary.LittleEndian to encode the integer:

  var size int64

  // Send

  var buf [8]byte
  binary.BigEndian.PutUint64(buf[:], uint64(size))
  _, err := w.Write(buf[:])

  // Receive

  var buf [8]byte
  _, err := io.ReadFull(r, buf[:])
  if err != nil {
      // handle error
  }
  size = int64(binary.BigEndian.Uint64(buf[:])

You can also use the binary.Read and binary.Write. Your application code will be a little shorter at the cost of type switches and other goo inside these functions.

A couple of points about the code in the question. The conversion

 string(fSize)

returns the UTF-8 representation of the rune fSize. It does not return a decimal encoding or binary encoding the value. Use the strconv packate to convert a numeric value to a decimal representation. Use the above mentioned binary package to convert to binary representation.

The sequence

connection.Read(buffer)
buffer = bytes.Trim(buffer, &quot;\x00&quot;)

trims away real data if the data happens to include a 0 byte at the ends. Read returns the number of bytes read. Use that length to slice the buffer:

n, err := connection.Read(buffer)
buffer = buffer[:n]

答案3

得分: 0

你不能使用string()将int转换为字符串,你需要使用strconv包。

connection.Write([]byte(strconv.FormatInt(fileInfo.Size(), 10)))
英文:

You can't use string() to cast from an int, you need to use the strconv package.

connection.Write([]byte(strconv.FormatInt(fileInfo.Size(), 10))

huangapple
  • 本文由 发表于 2014年9月27日 09:10:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/26070320.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定