tcp 服务器并发处理客户端请求范例

2.2 tcp 服务器并发处理客户端请求范例

并发:
    时间服务器
    当 client 链接,就给客户端响应,服务器端就给客户端返回一个当前时间

2.2.1 未作并发处理范例

server 端

package main

import (
    "fmt"
    "net"
    "time"
)

func main() {
    addr := "0.0.0.0:9999"
    protocol := "tcp"

    listens, err := net.Listen(protocol, addr)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 循环处理客户端链接
    for {
        conn, err := listens.Accept()
        if err != nil {
            fmt.Println(err)
            continue
        }
        fmt.Printf("客户端[%s]连接成功\n", conn.RemoteAddr())

        // 这里暂停 10 秒用来模拟客户端链接的过程比较久
        time.Sleep(10 * time.Second)
        // 发送时间
        fmt.Fprintln(conn, time.Now().Format("[2006-01-02 15:04:05]"))
        // 关闭客户端链接
        conn.Close()
        fmt.Printf("客户端[%s]退出\n", conn.RemoteAddr())
    }

    // 关闭服务器端链接
    listens.Close()
}

client 端

package main

import (
    "bufio"
    "fmt"
    "net"
    "time"
)

func main() {
    addr := "127.0.0.1:9999"
    protocol := "tcp"

    // 记录客户端的连接时间
    start := time.Now()
    conn, err := net.Dial(protocol, addr)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 客户端读取一行服务器端数据
    reader := bufio.NewReader(conn)
    fmt.Println(reader.ReadString('\n'))

    // 关闭连接
    conn.Close()

    // 记录客户端一共链接了多久
    fmt.Println(time.Now().Sub(start))
}

执行 server 端

我们通过观察会发现,一个客户端请求连接上了需要等待 10s 才知道请求结果,同时启动第二个客户端需要等待 18s 才能得到服务器端的响应

但是这个时间服务器如果会被多个客户端使用的时候,这里我在开启第二个客户端的时候,在隔了 10s 才响应了第二个客户端,如果当前这个程序被一百个客户端访问,那么是不是越往后连接的客户端,服务器端处理的时间越久。

由此就引出了我们并发的请求,不可能说多个客户端来请求服务器端越往后的客户端处理的时间越长,这种显然是不合理的

2.2.2 并发处理范例

如果我们需要开启并发处理,问题一定在 server 端,如果说我接受一个客户端我们能不能通过协程来处理这个请求呢?

我们这个 server 端的问题主要是出在客户端链接这一块,我们可以将客户端连接这一块的代码封装为一个协程也就是开启 goroutine

修改后的 server 端代码

package main

import (
    "fmt"
    "net"
    "time"
)

func main() {
    addr := "0.0.0.0:9999"
    protocol := "tcp"

    listens, err := net.Listen(protocol, addr)
    if err != nil {
        fmt.Println(err)
        return
    }

    // 循环处理客户端链接
    for {
        conn, err := listens.Accept()
        if err != nil {
            fmt.Println(err)
            continue
        }

        // 开启协程进行处理客户端请求
        go func() {
            fmt.Printf("客户端[%s]连接成功\n", conn.RemoteAddr())
            // 这里暂停 10 秒用来模拟客户端链接的过程比较久
            time.Sleep(10 * time.Second)
            // 发送时间
            fmt.Fprintln(conn, time.Now().Format("[2006-01-02 15:04:05]"))
            // 关闭客户端链接
            conn.Close()
            fmt.Printf("客户端[%s]退出\n", conn.RemoteAddr())
        }()
    }

    // 关闭服务器端链接
    listens.Close()
}

执行

通过执行我们会发现现在 server 端能够通过处理多个 客户端请求,由此借助了 goroutine 的好处

goroutine 严格遵循了 MPG 工作原理一个 goroutine 支持多个并发请求处理[典藏版] Golang 调度器 GMP 原理与调度全分析 | Go 技术论坛 (learnku.com)

评论

  1. zz
    3年前
    2021-7-10 17:10:35

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇