Go语言实现一个简单的并发聊天室的项目实战


Posted in Golang onMarch 18, 2022

写在前面

Go语言在很多方面天然的具备很多便捷性,譬如网络编程,并发编程。而通道则又是Go语言实现并发编程的重要工具,因为其承担着通道之间互相通信的重任。并且因为其本身就是并发安全的,所以在某些场景下是非常好用的。

并发聊天服务器

这里主要是实现一个简单的并发聊天服务器。首先,客户端可以在服务器中注册自己的信息(登录以及退出),客户端发出的所有的信息由服务器向各个客户端进行转发,或者换句话说是广播。

具体代码

服务端

说的再多,没有代码简单明了,直接上代码~

package main

import (
    "bufio"
    "fmt"
    "log"
    "net"
)
type client chan <- string //定义一个单向的向外发送数据的通道

var (
    entering = make(chan client)
    leaving = make(chan client)
    messages = make(chan string)
)

func main() {
    listener, err := net.Listen("tcp","localhost:8000")
    if err != nil {
        log.Fatal("network is broken", err)
    }
    go broadcaster()
    for {
        conn, err := listener.Accept()
        if err != nil {
            log.Print(err)
            continue
        }
        go handleConn1(conn)
    }
}
func broadcaster()  {
    clients := make(map[client]bool) //存储每个client的登录状态
    for{
        select {
        case msg := <-messages:
            for cli := range clients {
                cli <- msg
            }
        case cli := <-entering:
            clients[cli] = true
        case cli := <-leaving:
            delete(clients,cli)
            close(cli)
        }
    }
}

func handleConn1(conn net.Conn)  {
    ch := make(chan string)
    go clientWriter(conn, ch)
    who := conn.RemoteAddr().String()
    ch <- "You are " + who
    entering <- ch
    messages <- who + "has arrived"

    input := bufio.NewScanner(conn)
    for input.Scan() {
        messages <- who + ":" + input.Text()
    }

    leaving <- ch
    messages <- who + "has left"
    conn.Close()
}

func clientWriter(conn net.Conn, ch <- chan string)  {
    for msg := range ch {
        fmt.Fprintln(conn, msg)
    }
}

客户端

客户端相对简单,只是涉及到信息的发送和接受工作。

package main

import (
    "io"
    "log"
    "net"
    "os"
)

func main() {
    conn, err := net.Dial("tcp","localhost:8000")
    if err != nil {
        log.Fatal("Connected has been refused!",err)
    }
    defer conn.Close()
    go mesCopy(os.Stdout,conn)
    mesCopy(conn,os.Stdin)
}

func mesCopy(des io.Writer, res io.Reader)  {
    if _, err := io.Copy(des, res); err != nil {
        log.Print("wrong!")
    }
}

 总结

实现原理较为简单,所以代码并没有多少注释,如果有任何疑问,欢迎留言讨论。最后说一句,在MIT的课程中,其实并不是很推荐在并发编程中使用通道chan,除非你对其应用的场景和可能出现的情况有很好的把握,不然可能会出现很多不可预测的事情,譬如死锁(见另外一篇博客)。在这种时候,共享变量将会是一种很好的选择,具体查看go多线程实践。

到此这篇关于Go语言实现一个简单的并发聊天室的项目实战的文章就介绍到这了,更多相关Go语言 并发聊天室内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Golang 相关文章推荐
Golang二维切片初始化的实现
Apr 08 Golang
Go语言带缓冲的通道实现
Apr 26 Golang
golang 实现对Map进行键值自定义排序
Apr 28 Golang
对Golang中的FORM相关字段理解
May 02 Golang
goland 设置project gopath的操作
May 06 Golang
解决golang 关于全局变量的坑
May 06 Golang
Golang全局变量加锁的问题解决
May 08 Golang
go 实现简易端口扫描的示例
May 22 Golang
浅谈Go语言多态的实现与interface使用
Jun 16 Golang
golang fmt格式“占位符”的实例用法详解
Jul 04 Golang
K8s部署发布Golang应用程序的实现方法
Jul 16 Golang
手把手教你导入Go语言第三方库
Aug 04 Golang
浅谈GO中的Channel以及死锁的造成
Mar 18 #Golang
Golang 并发下的问题定位及解决方案
Mar 16 #Golang
如何利用golang运用mysql数据库
深入理解go缓存库freecache的使用
Feb 15 #Golang
Go语言读取txt文档的操作方法
Jan 22 #Golang
一文搞懂Golang 时间和日期相关函数
Go语言基础切片的创建及初始化示例详解
Nov 17 #Golang
You might like
PHP实现的连贯操作、链式操作实例
2014/07/08 PHP
使用Thinkphp框架开发移动端接口
2015/08/05 PHP
PHP模板引擎Smarty内建函数foreach,foreachelse用法分析
2016/04/11 PHP
php+mysql实现的二级联动菜单效果详解
2016/05/10 PHP
php fseek函数读取大文件两种方法
2016/10/12 PHP
thinkphp5 migrate数据库迁移工具
2018/02/20 PHP
Laravel 5.5 异常处理 &amp; 错误日志的解决
2019/10/17 PHP
[原创]静态页面也可以实现预览 列表不同的显示方式
2006/10/14 Javascript
javascript面向对象之二 命名空间
2011/02/08 Javascript
jQuery的学习步骤
2011/02/23 Javascript
JS中setInterval、setTimeout不能传递带参数的函数的解决方案
2013/04/28 Javascript
js 程序执行与顺序实现详解
2013/05/13 Javascript
jQuery学习笔记之 Ajax操作篇(二) - 数据传递
2014/06/23 Javascript
js电话号码验证方法
2015/09/28 Javascript
js实现超酷的照片墙展示效果图附源码下载
2015/10/08 Javascript
jQuery中inArray方法注意事项分析
2016/01/25 Javascript
JS小数转换为整数的方法分析
2017/01/07 Javascript
图解Javascript——作用域、作用域链、闭包
2017/03/21 Javascript
微信小程序实现多个按钮toggle功能的实例
2017/06/13 Javascript
vue点击按钮实现简单页面的切换
2020/09/08 Javascript
[59:00]OG vs TNC 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
python实现的一个火车票转让信息采集器
2014/07/09 Python
在Python中使用HTML模版的教程
2015/04/29 Python
Python使用turtule画五角星的方法
2015/07/09 Python
Python 实现淘宝秒杀的示例代码
2018/01/02 Python
python实现小球弹跳效果
2019/05/10 Python
Python批量修改图片分辨率的实例代码
2019/07/04 Python
美国高级工作服品牌:Carhartt
2018/01/25 全球购物
加拿大城市本地限时优惠:Buytopia.ca
2018/09/19 全球购物
阿迪达斯英国官方网站:adidas英国
2019/08/13 全球购物
Tessabit美国:集世界奢侈品和设计师品牌的意大利精品买手店
2020/06/29 全球购物
一道SQL面试题
2012/12/31 面试题
95%的面试官都会问到的50道Java线程题,附答案
2012/08/03 面试题
家长寄语大全
2014/04/02 职场文书
工业自动化专业自荐信范文
2014/04/10 职场文书
个人四风问题整改措施思想汇报
2014/10/04 职场文书