Go语言实现一个简单的并发聊天室的项目实战
作者:Sirius_7 发布时间:2024-02-15 03:40:33
标签:Go语言,并发聊天室
写在前面
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多线程实践。
来源:https://blog.csdn.net/weixin_38107316/article/details/116161658


猜你喜欢
- 将数据库中的数据保存在excel文件中有很多种方法,这里主要介绍pyExcelerator的使用。一、前期准备(不详细介绍MySQL)pyt
- pandas可以将读取到的表格型数据(文件不一定要是表格)转成DataFrame类型的数据结构,然后我们可以通过操作DataFrame进行数
- 1.命名规范1.库名、表名、字段名必须使用小写字母,并采用下划线分割。a)MySQL有配置参数lower_case_table_names,
- python语言本身没有提供const,但实际开发中经常会遇到需要使用const的情形,由于语言本身没有这种支出,因此需要使用一些技巧来实现
- 那就废话不多说,直接上代码吧!new_array = np.zeros((107,4))# 共107行 每行4列 初值为0>>&
- 一、使用NumPy读写文本文件在数据分析中,经常需要从文件中读取数据或将数据写入文件,常用的存储文件的格式有文本文件、CSV格式文件、二进制
- python 3.10支持match语句,3,10以下不支持。match语句接受一个表达式,并将其值与作为一个或多个case块给出的连续模式
- 因为主键可以唯一标识某一行记录,所以可以确保执行数据更新、删除的时候不会出现张冠李戴的错误。当然,其它字段可以辅助我们在执行这些操作时消除共
- 本文实例讲述了js实现黑色简易的滑动门网页tab选项卡效果。分享给大家供大家参考。具体如下:这是一款js实现的黑色风格网页滑动门菜单,虽然简
- 对于现在很多工业检测,特别是对一些精密的器件进行筛选,往往都是像素级别的,十分的精确。主要思想将图像转化为二值图像在对图像进行腐蚀/膨胀处理
- 项目中需要对 api 的接口进行限流,但是麻烦的是,api 可能有多个节点,传统的本地限流无法处理这个问题。限流的算法有很多,比如计数器法,
- 有时候想要把几张图放在一起plot,比较好对比,subplot和subplots都可以实现,具体对比可以查看参考博文。这里用matplotl
- 本文主要研究的是tornado 多进程模式的相关内容,具体如下。官方文档的helloworld实例中的启动方法:if __name__ ==
- 1 引言 在关系数据库(DB2,Oracle,Sybase,Informix和SQL Server)最小的恢复和交易单位为一个事务(Tran
- 理想高通滤波实现 python opencvimport numpy as np import cv2 from matplotlib im
- 《lnmp一键安装包》中需要获取ip地址,有2种情况:如果服务器只有私网地址没有公网地址,这个时候获取的IP(即私网地址)不能用来判断服务器
- 测试驱动开发(TDD)是一个迭代的开发周期,强调编写实际代码之前编写自动化测试。这个过程很简单: 先编写
- 什么是死锁,在Go的协程里面死锁通常就是永久阻塞了,你拿着我的东西,要我先给你然后再给我,我拿着你的东西又让你先给我,不然就不给你。我俩都这
- 之前写过一篇文章《EmEditor代码片段插件介绍》,现在项目越来越多,越来越大,不再用EmEditor,而用IntelliJ IDEA。这
- 01、文件操作文件是操作系统提供给用户/应用程序操作硬盘的一个虚拟的概念/接口用户/应用程序可以通过文件将数据永久保存在硬盘中用户/应用程序