交换数据需要实现协商好每次传的数据包长度,否则可能会造成数据的截断,接收的数据不正确
交换数据:
每次通信先读5个字节,这5个字节保存此次通信的长度。
根据长度定义buffer -> make([]byte,length)

  1. 写=>前5个字节=>length
  2. []byte("3") ->只有一个字节,可以使用Sprintf("%05d,xx)来占位前5个字节

示例:
server:

  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "io"
  6. "net"
  7. "os"
  8. "strconv"
  9. "strings"
  10. )
  11. // 写函数
  12. func write(conn net.Conn, txt string) error {
  13. // 本次要发送消息的字节长度
  14. length := len(txt)
  15. // 使用Sprintf用占位符的方式将长度写入第一跳消息;客户端和server端必须协商好,否则就会出现接收数据截断的情况
  16. _, err := conn.Write([]byte(fmt.Sprintf("%05d", length)))
  17. //判断是否有错
  18. if err != nil {
  19. fmt.Println(err)
  20. return err
  21. }
  22. //将真正的消息发送给客户端
  23. _, err = conn.Write([]byte(txt))
  24. if err != nil {
  25. fmt.Println(err)
  26. return err
  27. }
  28. return nil
  29. }
  30. //读取消息的函数
  31. func read(conn net.Conn) (string, error) {
  32. //定义读取消息前5个字节的buffer,用于确定本次消息的总长度
  33. lengthBytes := make([]byte, 5)
  34. //连接客户端读取消息的总长度
  35. _, err := conn.Read(lengthBytes)
  36. if err != nil {
  37. fmt.Println(err)
  38. return "", err
  39. }
  40. //将接收的字节切片转换成字符串,然后再转换成int类型
  41. length, err := strconv.Atoi(string(lengthBytes))
  42. if err != nil {
  43. fmt.Println(err)
  44. return "", err
  45. }
  46. //制作总消息长度字节切片 buffer
  47. ctx := make([]byte, length)
  48. //接收来自客户端的总消息
  49. _, err = conn.Read(ctx)
  50. if err != nil {
  51. fmt.Println(err)
  52. return "", err
  53. }
  54. return string(ctx), nil
  55. }
  56. // 编写文本消息
  57. func input(prompt string) string {
  58. fmt.Print(prompt)
  59. scanner := bufio.NewScanner(os.Stdin)
  60. scanner.Scan()
  61. return strings.TrimSpace(scanner.Text())
  62. }
  63. func main() {
  64. addr := "127.0.0.1:8888" //host:port
  65. // 如果需要在机器外部访问需要使用 外部可以访问的网卡IP
  66. // 多块网卡呢 0.0.0.0:8888 :8888
  67. protocol := "tcp"
  68. // 1. 监听服务
  69. listener, err := net.Listen(protocol, addr)
  70. if err != nil {
  71. fmt.Println(err)
  72. return
  73. }
  74. fmt.Println(listener.Addr())
  75. for { //使用循环接收客户端的消息
  76. // 2. 接收客户端请求
  77. conn, err := listener.Accept()
  78. if err != nil {
  79. fmt.Println(err)
  80. } else {
  81. fmt.Printf("客户端[%s]连接成功\n", conn.RemoteAddr())
  82. // 3. 与客户都端交换数据
  83. for {
  84. //调用读函数,读取客户端消息
  85. txt, err := read(conn)
  86. if err != nil {
  87. if err != io.EOF { //需要判断消息是否发送完毕,如果发送完毕会返回一个EOF的错误信息,然后关闭连接,否则连接不会
  88. fmt.Println(err)
  89. }
  90. break
  91. }
  92. fmt.Printf("客户端发送: %s\n", txt)
  93. //从consol中输入本文信息
  94. txt = input("请输入信息: ")
  95. if txt == "exit" {
  96. break
  97. }
  98. //将文本信息写入到连接中,发送给客户端
  99. err = write(conn, txt)
  100. if err != nil {
  101. if err != io.EOF {
  102. fmt.Println(err)
  103. }
  104. break
  105. }
  106. }
  107. // conn.Write()
  108. // 4. 关闭客户端连接
  109. conn.Close()
  110. fmt.Println("客户端关闭")
  111. }
  112. }
  113. // 5. 关闭服务器
  114. listener.Close()
  115. }
文档更新时间: 2021-08-25 17:33   作者:张尚