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 29 Golang
go语言中GOPATH GOROOT的作用和设置方式
May 05 Golang
Golang生成Excel文档的方法步骤
Jun 09 Golang
Go语言并发编程 sync.Once
Oct 16 Golang
Go 语言中 20 个占位符的整理
Oct 16 Golang
浅谈GO中的Channel以及死锁的造成
Mar 18 Golang
详解Golang如何优雅的终止一个服务
Mar 21 Golang
Go语言grpc和protobuf
Apr 13 Golang
Golang MatrixOne使用介绍和汇编语法
Apr 19 Golang
Golang解析JSON对象
Apr 30 Golang
Golang 入门 之url 包
May 04 Golang
Go调用Rust方法及外部函数接口前置
Jun 14 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获取网络文件的实现代码
2010/01/01 PHP
php一个解析字符串排列数组的方法
2015/05/12 PHP
WordPress用户登录框密码的隐藏与部分显示技巧
2015/12/31 PHP
QQ登录简单实现代码
2021/03/09 Javascript
safari,opera嵌入iframe页面cookie读取问题解决方法
2010/06/23 Javascript
jQuery总体架构的理解分析
2011/03/07 Javascript
判断window.onload是否多次使用的方法
2014/09/21 Javascript
20个实用的JavaScript技巧分享
2014/11/28 Javascript
每天一篇javascript学习小结(Function对象)
2015/11/16 Javascript
基于JQuery打造无缝滚动新闻步骤详解
2016/03/31 Javascript
简单了解JavaScript操作XPath的一些基本方法
2016/06/03 Javascript
JS 数字转换为大写金额的简单实例
2016/08/04 Javascript
AngularJS ng-repeat指令中使用track by子语句解决重复数据遍历错误问题
2017/01/21 Javascript
jQuery中绑定事件bind() on() live() one()的异同
2017/02/23 Javascript
jQuery实现点击DIV同时点击CheckBox,并为DIV上背景色的实例
2017/12/18 jQuery
关于laydate.js加载laydate.css路径错误问题解决
2017/12/27 Javascript
浅谈Fetch 数据交互方式
2018/12/20 Javascript
nodejs实现获取本地文件夹下图片信息功能示例
2019/06/22 NodeJs
使用Node.js实现base64和png文件相互转换的方法
2020/03/11 Javascript
[01:03:38]2014 DOTA2国际邀请赛中国区预选赛5.21 CNB VS CIS
2014/05/22 DOTA
[10:28]2018DOTA2国际邀请赛寻真——VGJ.S寻梦之路
2018/08/15 DOTA
讲解python参数和作用域的使用
2013/11/01 Python
pycharm下查看python的变量类型和变量内容的方法
2018/06/26 Python
Python之inspect模块实现获取加载模块路径的方法
2018/10/16 Python
python实现在函数中修改变量值的方法
2019/07/16 Python
python selenium自动化测试框架搭建的方法步骤
2020/06/14 Python
html5 标签
2009/07/16 HTML / CSS
英国版MAC彩妆品牌:Illamasqua
2018/04/18 全球购物
大学生工作求职信
2014/06/23 职场文书
安全生产知识竞赛活动总结
2014/07/07 职场文书
大学生入党积极分子自我评价
2014/09/20 职场文书
民主生活会对照检查材料范文
2014/10/01 职场文书
小学生思想品德评语
2014/12/31 职场文书
结婚保证书
2015/01/16 职场文书
病假条格式范文
2015/08/17 职场文书
Nginx工作模式及代理配置的使用细节
2022/03/21 Servers