教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Go 群聊 ( goroutine )

Go 群聊 ( goroutine )

发布时间:2023-01-28   编辑:jiaochengji.com
教程集为您提供Go 群聊 ( goroutine )等资源,欢迎您收藏本站,我们将为您提供最新的Go 群聊 ( goroutine )资源

前言

看了无闻老师的一节关于 goroutine 与 channel 的讲解课堂,感觉不是很明白,所以决定来实现一个聊天室的功能

为什么是群聊呢?

因为群聊相对逻辑简单些

注:本栗子只用到了 goroutine 并没有用到 channel

概述

1.聊天室的组成

聊天室分为两个部分,分别是:

  • 服务端
  • 客户端

然后,一般情况下我们互相聊天使用的都只是客户端而已,服务端只是起到调度的作用

2.信息发送与接收的流程

假设我们有 服务端(S) 客户端(C1) 客户端(C2) 客户端(C3)

并且 S 已经 与 C1 C2 C3 建立了连接

理论上的流程是这样的:

  1. C1S 发出信息
  2. S 接收到信息
  3. S 将接收到的信息广播给 C2 C3
  4. C2 C3 接收信息

实践

1.服务端

1) 代码

package main

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

// 客户端 map 
var client_map =  make(map[string]*net.TCPConn)

// 监听请求
func listen_client(ip_port string) {
    tcpAddr, _ := net.ResolveTCPAddr("tcp", ip_port)
    tcpListener, _ := net.ListenTCP("tcp", tcpAddr)
    for {// 不停地接收
        client_con, _ := tcpListener.AcceptTCP()// 监听请求连接
        client_map[client_con.RemoteAddr().String()] = client_con// 将连接添加到 map
        go add_receiver(client_con)
        fmt.Println("用户 : ", client_con.RemoteAddr().String(), " 已连接.")
    }
}

// 向连接添加接收器
func add_receiver(current_connect *net.TCPConn) {
    for {
        byte_msg := make([]byte, 2048)
        len, err := current_connect.Read(byte_msg)
        if err != nil { current_connect.Close() }
        fmt.Println(string(byte_msg[:len]))
        msg_broadcast(byte_msg[:len], current_connect.RemoteAddr().String())
    }
}

// 广播给所有 client
func msg_broadcast(byte_msg []byte, key string) {
    for k, con := range client_map {
        if k != key { con.Write(byte_msg) }
    }
}

// 主函数
func main() {
    fmt.Println("服务已启动...")
    time.Sleep(1 * time.Second)
    fmt.Println("等待客户端请求连接...")
    go listen_client("127.0.0.1:1801")
    select{}
}    

b) 描述

可以看到,撇开 main 函数,一共有 2 个 routine,分别是:

  1. 监听连接
  2. 接收消息(广播消息也在这里)

2.客户端

a) 代码

package main

import (
    "fmt"
    "net"
    "os"
    "bufio"
)

// 用户名
var login_name string

// 本机连接
var self_connect *net.TCPConn

// 读取行文本
var reader = bufio.NewReader(os.Stdin)

// 建立连接
func connect(addr string) {
    tcp_addr, _ := net.ResolveTCPAddr("tcp", addr) // 使用tcp
    con, err := net.DialTCP("tcp", nil, tcp_addr) // 拨号
    self_connect = con
    if err != nil {
        fmt.Println("服务器连接失败")
        os.Exit(1)
    }
    go msg_sender()
    go msg_receiver()
}

// 消息接收器
func msg_receiver() {
    buff := make([]byte, 2048)
    for {
        len, _ := self_connect.Read(buff) // 读取消息
        fmt.Println(string(buff[:len]))
    }
}

// 消息发送器
func msg_sender() {
    for {
        read_line_msg, _, _ := reader.ReadLine()
        read_line_msg = []byte(login_name   " : "   string(read_line_msg))
        self_connect.Write(read_line_msg)
    }
}

// 主函数
func main() {
    fmt.Println("请问您怎么称呼?")
    name, _, _ := reader.ReadLine()
    login_name = string(name)
    connect("127.0.0.1:1801")
    select{}
}

b) 描述

同样,客户端也是有两个 routine 组成:

  1. 消息接收器
  2. 消息发送器

建立连接在主线程完成

3.效果图

a) 服务端

b) 客户端_1

c) 客户端_2

结尾

这里并没有用到 channel

小栗子仅为经验总结,学习交流而记


到此这篇关于“Go 群聊 ( goroutine )”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
Golang 网络编程实现的高并发聊天程序
Go语言爱好者周刊:第 78 期 — 这道关于 goroutine 的题
Go:Goroutine 的切换过程实际上涉及了什么
goroutine与调度器
Golang调度与MPG
详解defer实现机制(附上三道面试题)
简单理解 Goroutine 是如何工作的
Goroutine并发调度模型深度解析&手撸一个协程池
Goroutine的调度分析(一)
Golang并发原理及GPM调度策略(一)

[关闭]
~ ~