在Go中通过套接字发送int64的正确方法

在Go中通过套接字发送int64的正确方法

问题描述:

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
}

我正在尝试通过golang中的TCP发送int64,但是我的接收方打印得到一个不同的数字,然后 我发出的。 p>

  //客户端和服务器上的缓冲区
buffer:= make([] byte,1024)
 
 // Sender  
fileInfo,错误:= os.Stat(fileName)
if错误!= nil {
 fmt.Println(“打开文件时发生错误”)
} 
var fSize int = int(fileInfo.Size())
 \  nconnection.Write([] byte(string(fSize)))
 
 
 // Receiver 
connection.Read(buffer)
 
fileSize:= new(big.Int).SetBytes(bytes.Trim(buffer)  ,“ \ x00”))。Int64()
if err!= nil {
 fmt.Println(“无效的文件大小”)
 fileSize = 0 
} 
  code>  pre> \  n  div>

Using binary.Write / binary.Read:

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

//receiver
var size int64
err := binary.Read(connection, binary.LittleEndian, &size)
if err != nil {
    fmt.Println("err:", 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<<64-1) 

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))

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, "\x00")

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]