正常来说,我们发送和接收数据时,是像下面这样的:
// 发送端
func main() {
conn, _ := net.Dial("tcp", "127.0.0.1:8889")
data := []byte("hello world")
conn.Write(data)
fmt.Println("成功发送: ", string(data))
}
// 接收端
func main() {
listen, _ := net.Listen("tcp", "0.0.0.0:8889")
conn, _ := listen.Accept()
data := make([]byte, 1024)
conn.Read(data)
fmt.Println("成功接收: ", string(data))
}
运行结果如下:
这样看似没问题,但实际上还是存在着一定的风险(如数据丢失、解析错误…),这时就需要在发送和接受时对数据进行校验来确保交互的稳定性和安全性。
我们通常利用传输数据的长度来进行校验,思路如下:发送端先发送数据长度len1,再发送数据本体。接收端先接收到数据长度len1,再接收到数据本体,然后将数据本体的程度与数据长度len1进行比较,若二者相等则确认数据传输成功。
上代码
// 发送端
func main() {
conn, _ := net.Dial("tcp", "127.0.0.1:8889")
data := []byte("hello world")
// 发送data的长度len1
len1 := make([]byte, len(data))
dataLen := uint32(len(data))
binary.BigEndian.PutUint32(len1[:4], dataLen)
conn.Write(len1[:4])
// 发送data本体
conn.Write(data)
fmt.Println("成功发送: ", string(data))
}
// 接收端
func main() {
listen, _ := net.Listen("tcp", "0.0.0.0:8889")
conn, _ := listen.Accept()
// 接收到 data 的长度
len1:= make([]byte, 1024)
realLen, _ := conn.Read(len1[:4])
dataLen := binary.BigEndian.Uint32(len1[:4])// 将 data 的长度由 []byte 转为 uint32
// 接收到 data
data := make([]byte, 1024)
realLen, _ = conn.Read(data[:dataLen])
// 在这里进行校验
if realLen != int(dataLen) {
fmt.Println("数据在传输时出现问题")
return
}
fmt.Println("成功接收: ", string(data))
}
这样,我们就在接收端初步实现了数据的校验。
众所周知,Read()函数和Write()函数都可以实际传输了多少长度(字节),所以我们可以根据这个来完善一下数据的校验。
思路:在每次传输数据(Read或Write)时,我们根据返回的传输长度进行判断。
例如:
realLen, _ := conn.Write(buf[:4])
if realLen != 4 {
fmt.Println("数据在传输时出现问题")
return
}
realLen, _ = conn.Write(data)
if realLen != int(dataLen) {
fmt.Println("数据在传输时出现问题")
return
}
在我们之前的代码中完善这个校验:
// 发送端
func main() {
conn, _ := net.Dial("tcp", "127.0.0.1:8889")
data := []byte("hello world")
// 发送data的长度len1
len1 := make([]byte, len(data))
dataLen := uint32(len(data))
binary.BigEndian.PutUint32(len1[:4], dataLen)
conn.Write(len1[:4])
// 完善校验
if realLen != 4 {
fmt.Println("数据在传输时出现问题")
return
}
// 发送data本体
conn.Write(data)
// 完善校验
if realLen != int(dataLen) {
fmt.Println("数据在传输时出现问题")
return
}
fmt.Println("成功发送: ", string(data))
}
// 接收端
func main() {
listen, _ := net.Listen("tcp", "0.0.0.0:8889")
conn, _ := listen.Accept()
// 接收到 data 的长度
len1:= make([]byte, 1024)
realLen, _ := conn.Read(len1[:4])
dataLen := binary.BigEndian.Uint32(len1[:4])// 将 data 的长度由 []byte 转为 uint32
// 完善校验
if realLen != 4 {
fmt.Println("数据在传输时出现问题")
return
}
// 接收到 data
data := make([]byte, 1024)
realLen, _ = conn.Read(data[:dataLen])
// 完善校验
if realLen != int(dataLen) {
fmt.Println("数据在传输时出现问题")
return
}
// 在这里进行校验
if realLen != int(dataLen) {
fmt.Println("数据在传输时出现问题")
return
}
fmt.Println("成功接收: ", string(data))
}
这样,就实现了对数据的长度的校验。