示例代码

  1. 目录结构:

    |—— tcp/   // 根目录
    ****|—— client/
    ********|—— main.go  // 客户端
    ****|—— server/
    ********|—— main.go  // 服务端
  2. server/main.go:

     package main
    
     import (
         "bufio"
         "fmt"
         "net"
         "os"
         "os/signal"
         "syscall"
         "time"
     )
    
     const (
         Address = "localhost:9011"
     )
    
     // 处理函数
     func process(conn net.Conn) {
         defer conn.Close() // 关闭连接
    
         // 发送消息
         go func() {
             for {
                 _, err := conn.Write([]byte("hello from server!"))
                 if err != nil {
                     fmt.Println(err.Error())
                     return
                 }
                 time.Sleep(3 * time.Second)
             }
         }()
         // 接收消息
         for {
             reader := bufio.NewReader(conn)
             var buf [128]byte
             n, err := reader.Read(buf[:]) // 读取数据
             if err != nil {
                 fmt.Println(err.Error())
                 return
             }
             data := buf[:n]
             fmt.Println("message from client:", string(data))
         }
     }
    
     func main() {
         quit := make(chan os.Signal, 1) // 退出信号
         signal.Notify(quit, syscall.SIGKILL, syscall.SIGQUIT, syscall.SIGINT, syscall.SIGTERM)
         //// 将句柄存入 .sock 文件
         //srv, err := net.Listen("unix", "./tmp.sock")
         srv, err := net.Listen("tcp", Address)
         if err != nil {
             fmt.Println("Listen() failed, err: ", err)
             return
         }
         go shutdown(quit, srv)
         fmt.Printf("server running at:%s \n", Address)
         for {
             conn, err := srv.Accept() // 监听客户端的连接请求
             if err != nil {
                 fmt.Println("Accept() failed, err: ", err)
                 continue
             }
             go process(conn) // 启动一个 goroutine 来处理客户端的连接请求
         }
     }
    
     func shutdown(quit chan os.Signal, srv net.Listener) {
         <-quit
         fmt.Println("server shutdown...")
         if err := srv.Close(); err != nil {
             fmt.Println("shutdown error:", err)
         }
         os.Exit(0)
     }
  3. 启动 server/main.go(略)

  4. client/main.go:

     package main
    
     import (
         "fmt"
         "net"
         "os"
         "os/signal"
         "syscall"
         "time"
     )
    
     const (
         Address = "localhost:9011"
     )
    
     var msgChan = make(chan string)
    
     func tcpClient() {
         quit := make(chan os.Signal, 1)
         signal.Notify(quit, syscall.SIGKILL, syscall.SIGQUIT, syscall.SIGINT, syscall.SIGTERM)
         //// 从 .sock 文件中获取句柄
         //conn, err := net.Dial("unix", "./tmp.sock")
         conn, err := net.Dial("tcp", Address)
         if err != nil {
             panic(err)
         }
         defer conn.Close() // 关闭 TCP 连接
    
         // 发送消息
         go func() {
             for {
                 select {
                 case msg := <-msgChan:
                     _, err := conn.Write([]byte(msg))
                     if err != nil {
                         fmt.Println("write error:", err)
                     }
                 case <-quit:
                     fmt.Println("control + c pressed!")
                     _, err := conn.Write([]byte("client closed!"))
                     if err != nil {
                         fmt.Println("send close message error:", err)
                         os.Exit(0)
                     }
                     if err := conn.Close(); err != nil {
                         fmt.Println("conn close error:", err)
                         os.Exit(0)
                     }
                     os.Exit(0)
                 }
             }
         }()
         // 接收消息
         for {
             buf := [512]byte{}
             n, err := conn.Read(buf[:])
             if err != nil {
                 fmt.Println("Error in receive:", err)
                 return
             }
             msg := buf[:n]
             fmt.Println("message from server:", string(msg))
         }
     }
    
     func main() {
         go tcpClient()
         // 将要发送到服务端的消息传递到消息管道
         for i := 0; i < 3; i++ {
             msgChan <- "hello from client!"
             time.Sleep(3 * time.Second)
         }
         select {}
     }
  5. 启动 client/main.go(略)

文档更新时间: 2024-04-20 10:57   作者:lee