• go实现tcp 服务器


    我们将使用 TCP 协议和协程范式编写一个简单的客户端-服务器应用,一个(web)服务器应用需要响应众多客户端的并发请求:Go 会为每一个客户端产生一个协程用来处理请求。我们需要使用 net 包中网络通信的功能。它包含了处理 TCP/IP 以及 UDP 协议、域名解析等方法。

    服务器端代码是一个单独的文件:

    示例 1 server.go

    package main
    
    import (
        "fmt"
        "net"
    )
    
    func main() {
        fmt.Println("Starting the server ...")
        // 创建 listener
        listener, err := net.Listen("tcp", "localhost:50000")
        if err != nil {
            fmt.Println("Error listening", err.Error())
            return //终止程序
        }
        // 监听并接受来自客户端的连接
        for {
            conn, err := listener.Accept()
            if err != nil {
                fmt.Println("Error accepting", err.Error())
                return // 终止程序
            }
            go doServerStuff(conn)
        }
    }
    
    func doServerStuff(conn net.Conn) {
        for {
            buf := make([]byte, 512)
            len, err := conn.Read(buf)
            if err != nil {
                fmt.Println("Error reading", err.Error())
                return //终止程序
            }
            fmt.Printf("Received data: %v
    ", string(buf[:len]))
        }
    }

    在 main() 中创建了一个 net.Listener 类型的变量 listener,他实现了服务器的基本功能:用来监听和接收来自客户端的请求(在 localhost 即 IP 地址为 127.0.0.1 端口为 50000 基于TCP协议)。Listen() 函数可以返回一个 error 类型的错误变量。用一个无限 for 循环的 listener.Accept() 来等待客户端的请求。客户端的请求将产生一个 net.Conn 类型的连接变量。然后一个独立的协程使用这个连接执行 doServerStuff(),开始使用一个 512 字节的缓冲 data 来读取客户端发送来的数据,并且把它们打印到服务器的终端,len 获取客户端发送的数据字节数;当客户端发送的所有数据都被读取完成时,协程就结束了。这段程序会为每一个客户端连接创建一个独立的协程。必须先运行服务器代码,再运行客户端代码。

    客户端代码写在另一个文件 client.go 中:

    示例 2 client.go

    package main
    
    import (
        "bufio"
        "fmt"
        "net"
        "os"
        "strings"
    )
    
    func main() {
        //打开连接:
        conn, err := net.Dial("tcp", "localhost:50000")
        if err != nil {
            //由于目标计算机积极拒绝而无法创建连接
            fmt.Println("Error dialing", err.Error())
            return // 终止程序
        }
    
        inputReader := bufio.NewReader(os.Stdin)
        fmt.Println("First, what is your name?")
        clientName, _ := inputReader.ReadString('
    ')
        // fmt.Printf("CLIENTNAME %s", clientName)
        trimmedClient := strings.Trim(clientName, "
    ") // Windows 平台下用 "
    ",Linux平台下使用 "
    "
        // 给服务器发送信息直到程序退出:
        for {
            fmt.Println("What to send to the server? Type Q to quit.")
            input, _ := inputReader.ReadString('
    ')
            trimmedInput := strings.Trim(input, "
    ")
            // fmt.Printf("input:--%s--", input)
            // fmt.Printf("trimmedInput:--%s--", trimmedInput)
            if trimmedInput == "Q" {
                return
            }
            _, err = conn.Write([]byte(trimmedClient + " says: " + trimmedInput))
        }
    }

    客户端通过 net.Dial 创建了一个和服务器之间的连接。

    它通过无限循环从 os.Stdin 接收来自键盘的输入,直到输入了“Q”。注意裁剪   和   字符(仅 Windows 平台需要)。裁剪后的输入被 connection 的 Write 方法发送到服务器。

    当然,服务器必须先启动好,如果服务器并未开始监听,客户端是无法成功连接的。

    如果在服务器没有开始监听的情况下运行客户端程序,客户端会停止并打印出以下错误信息:对tcp 127.0.0.1:50000发起连接时产生错误:由于目标计算机的积极拒绝而无法创建连接

    可以同时启动多个客户端程序。

    一下是服务器的输出:

    PS C:Users20928gosrcgo_code> go run server.g   erveo
    Starting the server ...
    Received data: 张三 says: 你好,我叫张三
    Received data: 李四 says: 你好,我叫李四,很高兴认识你
    Received data: 张三 says: 你来自哪里?
    Received data: 李四 says: 我来自中国
    Received data: 李四 says: 北京

    在网络编程中 net.Dial 函数是非常重要的,一旦你连接到远程系统,函数就会返回一个 Conn 类型的接口,我们可以用它发送和接收数据。Dial 函数简洁地抽象了网络层和传输层。所以不管是 IPv4 还是 IPv6,TCP 或者 UDP 都可以使用这个公用接口。

    参考链接:https://github.com/unknwon/the-way-to-go_ZH_CN/blob/master/eBook/15.1.md

  • 相关阅读:
    Php7安装pdo_pgsql,pgsql扩展
    Laravel 实时监听打印 SQL
    windows 下安装docker依赖boot2docker镜像默认用户和密码
    win7下安装virtual box后启动报错
    phpstorm 不能自动打开上次的历史文件
    BZOJ1001 [BeiJing2006]狼抓兔子 平面图转对偶图,最小割转最短路
    BZOJ1098 [POI2007]办公楼biu
    POJ1410 Intersection
    HDU3336 Count the string
    HDU2594 Simpsons’ Hidden Talents [KMP]
  • 原文地址:https://www.cnblogs.com/lfri/p/11769254.html
Copyright © 2020-2023  润新知