• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
正在输入>
博客园    首页    新随笔    联系   管理    订阅  订阅

GO学习笔记(9)

九. 网络编程 , 直接上代码

  9.1 tcp协议

    9.1.1. 基本使用

// server端代码
package main import (
"bufio" "fmt" "io" "net" ) func main() { listen, err := net.Listen("tcp", "127.0.0.1:50001") if err != nil { fmt.Println("监听端口失败:", err) return } fmt.Println("tcp服务已经启动") for { conn, err := listen.Accept() if err != nil { fmt.Println("连接失败:", err) continue } go process1(conn) // 启动一个goroutine处理连接 } } // 简单使用 func process1(conn net.Conn) { defer conn.Close() // 关闭连接 for { reader := bufio.NewReader(conn) var buf [128]byte n, err := reader.Read(buf[:]) // 读取数据 if err != nil { fmt.Println("读取数据失败:", err) break } recvStr := string(buf[:n]) fmt.Println("收到客户端发来的数据:", recvStr) conn.Write([]byte("服务器说: " + recvStr)) // 发送数据 } }

 

// client端代码
package main import (
"bufio" "fmt" "net" "os" "strings" ) func main() { demo1() } // 简单使用 func demo1() { conn, err := net.Dial("tcp", "127.0.0.1:50001") if err != nil { fmt.Println("连接失败 :", err) return } defer conn.Close() // 关闭连接 inputReader := bufio.NewReader(os.Stdin) for { input, _ := inputReader.ReadString('\n') // 读取用户输入 inputInfo := strings.Trim(input, "\r\n") if strings.ToUpper(inputInfo) == "Q" { // 如果输入q就退出 return } _, err = conn.Write([]byte(inputInfo)) // 发送数据 if err != nil { return } buf := [512]byte{} n, err := conn.Read(buf[:]) // 接受数据 if err != nil { fmt.Println("接收服务器数据失败:", err) return } fmt.Println("接收服务器数据: ", string(buf[:n])) } }

 

     9.1.2. 粘包问题

// server端代码
package main import (
"bufio" "fmt" "io" "net" ) func main() { listen, err := net.Listen("tcp", "127.0.0.1:50001") if err != nil { fmt.Println("监听端口失败:", err) return } fmt.Println("tcp服务已经启动") for { conn, err := listen.Accept() if err != nil { fmt.Println("连接失败:", err) continue } go process2(conn) // 启动一个goroutine处理连接 } } // 粘包 func process2(conn net.Conn) { defer conn.Close() reader := bufio.NewReader(conn) var buf [1024]byte for { n, err := reader.Read(buf[:]) if err == io.EOF { break } if err != nil { fmt.Println("read from client failed, err:", err) break } recvStr := string(buf[:n]) fmt.Println("收到client发来的数据:", recvStr) // 收到client发来的数据: 完蛋了,粘包了完蛋了,粘包了完蛋了,粘包了完蛋了,粘包了完蛋了,粘包了完蛋了,粘包了完蛋了,粘包了完蛋了,粘包了完蛋了,粘包了完蛋了,粘包了完蛋了,粘包了 // 收到client发来的数据: 完蛋了,粘包了完蛋了,粘包了完蛋了,粘包了完蛋了,粘包了完蛋了,粘包了完蛋了,粘包了完蛋了,粘包了完蛋了,粘包了完蛋了,粘包了 } }

 

// client端代码
package main import (
"bufio" "fmt" "net" "os" "strings" ) func main() { demo2() } // 粘包产生的原因: // 1.由Nagle算法造成的发送端的粘包:Nagle算法是一种改善网络传输效率的算法。简单来说就是当我们提交一段数据给TCP发送时,TCP并不立刻发送此段数据,而是等待一小段时间看看在等待期间是否还有要发送的数据,若有则会一次把这两段数据发送出去。 // 2.接收端接收不及时造成的接收端粘包:TCP会把接收到的数据存在自己的缓冲区中,然后通知应用层取数据。当应用层由于某些原因不能及时的把TCP的数据取出来,就会造成TCP缓冲区中存放了几段数据。 func demo2() { conn, err := net.Dial("tcp", "127.0.0.1:50001") if err != nil { fmt.Println("连接失败 :", err) return } defer conn.Close() // 关闭连接 msg := `完蛋了,粘包了` for i := 0; i < 20; i++ { conn.Write([]byte(msg)) } }

 

    9.1.3. 解决粘包问题: 封包

// 封包解包代码
package proto import (
"bufio" "bytes" "encoding/binary" ) // Encode 将消息编码 func Encode(message string) ([]byte, error) { // 读取消息的长度,转换成int32类型(占4个字节) var length = int32(len(message)) var pkg = new(bytes.Buffer) // 写入消息头 err := binary.Write(pkg, binary.LittleEndian, length) if err != nil { return nil, err } // 写入消息实体 err = binary.Write(pkg, binary.LittleEndian, []byte(message)) if err != nil { return nil, err } return pkg.Bytes(), nil } // Decode 解码消息 func Decode(reader *bufio.Reader) (string, error) { // 读取消息的长度 lengthByte, _ := reader.Peek(4) // 读取前4个字节的数据 lengthBuff := bytes.NewBuffer(lengthByte) var length int32 err := binary.Read(lengthBuff, binary.LittleEndian, &length) if err != nil { return "", err } // Buffered返回缓冲中现有的可读取的字节数。 if int32(reader.Buffered()) < length+4 { return "", err } // 读取真正的消息数据 pack := make([]byte, int(4+length)) _, err = reader.Read(pack) if err != nil { return "", err } return string(pack[4:]), nil }

 

// sever端代码
package main import (
"bufio" "fmt" "github.com/icanyou/demo/socket/proto" "io" "net" ) func main() { listen, err := net.Listen("tcp", "127.0.0.1:50001") if err != nil { fmt.Println("监听端口失败:", err) return } fmt.Println("tcp服务已经启动") for { conn, err := listen.Accept() if err != nil { fmt.Println("连接失败:", err) continue } go process3(conn) // 启动一个goroutine处理连接 } }// 解决粘包 func process3(conn net.Conn) { defer conn.Close() reader := bufio.NewReader(conn) for { msg, err := proto.Decode(reader) if err == io.EOF { return } if err != nil { fmt.Println("解码失败:", err) return } fmt.Println("收到client发来的数据:", msg) } }

 

// client端代码
package main import (
"bufio" "fmt" "github.com/icanyou/demo/socket/proto" "net" "os" "strings" ) func main() { demo3() }// 处理粘包 func demo3() { conn, err := net.Dial("tcp", "127.0.0.1:50001") if err != nil { fmt.Println("dial failed, err", err) return } defer conn.Close() for i := 0; i < 20; i++ { msg := `会不会粘包?` data, err := proto.Encode(msg) if err != nil { fmt.Println("encode msg failed, err:", err) return } conn.Write(data) } }

  9.2. http

// server端代码
package main import (
"fmt" "net/http" ) func main() { http.HandleFunc("/", handle) http.ListenAndServe("127.0.0.1:8000", nil) } // handler函数 func handle(w http.ResponseWriter, r *http.Request) { fmt.Println(r.RemoteAddr, "连接成功") fmt.Println("method:", r.Method) fmt.Println("url:", r.URL.Path) fmt.Println("header:", r.Header) fmt.Println("body:", r.Body) w.Write([]byte("hello world")) }

 

// client端代码
package main import (
"fmt" "io" "net/http" ) func main() { resp, _ := http.Get("http://127.0.0.1:8000/") defer resp.Body.Close() fmt.Println(resp.Status) fmt.Println(resp.Header) buf := make([]byte, 1024) for { // 接收服务端信息 n, err := resp.Body.Read(buf) if err != nil && err != io.EOF { fmt.Println(err) return } else { fmt.Println("读取完毕") res := string(buf[:n]) fmt.Println(res) break } } }

   9.3. websocket

 

posted @ 2020-08-11 15:51  正在输入>  阅读(157)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3