交换数据需要实现协商好每次传的数据包长度,否则可能会造成数据的截断,接收的数据不正确
交换数据:
每次通信先读5个字节,这5个字节保存此次通信的长度。
根据长度定义buffer -> make([]byte,length)
写=>前5个字节=>length
[]byte("3") ->只有一个字节,可以使用Sprintf("%05d,xx)来占位前5个字节
示例:
server:
package main
import (
"bufio"
"fmt"
"io"
"net"
"os"
"strconv"
"strings"
)
// 写函数
func write(conn net.Conn, txt string) error {
// 本次要发送消息的字节长度
length := len(txt)
// 使用Sprintf用占位符的方式将长度写入第一跳消息;客户端和server端必须协商好,否则就会出现接收数据截断的情况
_, err := conn.Write([]byte(fmt.Sprintf("%05d", length)))
//判断是否有错
if err != nil {
fmt.Println(err)
return err
}
//将真正的消息发送给客户端
_, err = conn.Write([]byte(txt))
if err != nil {
fmt.Println(err)
return err
}
return nil
}
//读取消息的函数
func read(conn net.Conn) (string, error) {
//定义读取消息前5个字节的buffer,用于确定本次消息的总长度
lengthBytes := make([]byte, 5)
//连接客户端读取消息的总长度
_, err := conn.Read(lengthBytes)
if err != nil {
fmt.Println(err)
return "", err
}
//将接收的字节切片转换成字符串,然后再转换成int类型
length, err := strconv.Atoi(string(lengthBytes))
if err != nil {
fmt.Println(err)
return "", err
}
//制作总消息长度字节切片 buffer
ctx := make([]byte, length)
//接收来自客户端的总消息
_, err = conn.Read(ctx)
if err != nil {
fmt.Println(err)
return "", err
}
return string(ctx), nil
}
// 编写文本消息
func input(prompt string) string {
fmt.Print(prompt)
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
return strings.TrimSpace(scanner.Text())
}
func main() {
addr := "127.0.0.1:8888" //host:port
// 如果需要在机器外部访问需要使用 外部可以访问的网卡IP
// 多块网卡呢 0.0.0.0:8888 :8888
protocol := "tcp"
// 1. 监听服务
listener, err := net.Listen(protocol, addr)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(listener.Addr())
for { //使用循环接收客户端的消息
// 2. 接收客户端请求
conn, err := listener.Accept()
if err != nil {
fmt.Println(err)
} else {
fmt.Printf("客户端[%s]连接成功\n", conn.RemoteAddr())
// 3. 与客户都端交换数据
for {
//调用读函数,读取客户端消息
txt, err := read(conn)
if err != nil {
if err != io.EOF { //需要判断消息是否发送完毕,如果发送完毕会返回一个EOF的错误信息,然后关闭连接,否则连接不会
fmt.Println(err)
}
break
}
fmt.Printf("客户端发送: %s\n", txt)
//从consol中输入本文信息
txt = input("请输入信息: ")
if txt == "exit" {
break
}
//将文本信息写入到连接中,发送给客户端
err = write(conn, txt)
if err != nil {
if err != io.EOF {
fmt.Println(err)
}
break
}
}
// conn.Write()
// 4. 关闭客户端连接
conn.Close()
fmt.Println("客户端关闭")
}
}
// 5. 关闭服务器
listener.Close()
}
文档更新时间: 2021-08-25 17:33 作者:张尚