zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    unexpected inconsistency;run fsck manually esxi断电后虚拟机启动故障
    centos 安装mysql 5.7
    centos 7 卸载mysql
    centos7 在线安装mysql5.6,客户端远程连接mysql
    ubuntu 14.04配置ip和dns
    centos7 上搭建mqtt服务
    windows eclipse IDE打开当前类所在文件路径
    git 在非空文件夹clone新项目
    eclipse中java build path下 allow output folders for source folders 无法勾选,该如何解决 eclipse中java build path下 allow output folders for source folders 无法勾选,
    Eclipse Kepler中配置JadClipse
  • 原文地址:https://www.cnblogs.com/lfri/p/11769254.html
Copyright © 2011-2022 走看看