英文:
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("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)
答案2
得分: 1
使用binary.BigEndian
或binary.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.Read
和binary.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, "\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]
答案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))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论