1、并发聊天服务器原理分析

2、并发聊天室

功能:

广播消息、广播上线、 查询在线用户、修改用户名、用户主动退出、超时处理

示例:

package main

import (
"fmt"
"net"
"strings"
"time"
) type Client struct {
C chan string //用户发送数据的管道
Name string //用户名
Addr string //网络地址
} //保存在线用户 cliAddr =====> Client
var onlineMap map[string]Client var messaage = make(chan string) //新开一个协程,转发消息,只要有消息来了,遍历map, 给map每个成员都发送此消息
func Manager() {
//给map分配空间
onlineMap = make(map[string]Client) for {
msg := <-messaage //没有消息前,这里会阻塞 //遍历map, 给map每个成员都发送此消息
for _, cli := range onlineMap {
cli.C <- msg
}
}
} func WriteMsgToClient(cli Client, conn net.Conn) {
for msg := range cli.C { //给当前客户端发送信息
conn.Write([]byte(msg + "\n"))
}
} func MakeMsg(cli Client, msg string) (buf string) {
buf = "[" + cli.Addr + "]" + cli.Name + ": " + msg return
} func HandleConn(conn net.Conn) { //处理用户链接
defer conn.Close() //获取客户端的网络地址
cliAddr := conn.RemoteAddr().String() //创建一个结构体, 默认,用户名和网络地址一样
cli := Client{make(chan string), cliAddr, cliAddr}
//把结构体添加到map
onlineMap[cliAddr] = cli //新开一个协程,专门给当前客户端发送信息
go WriteMsgToClient(cli, conn)
//广播某个在线
//messaage <- "[" + cli.Addr + "]" + cli.Name + ": login"
messaage <- MakeMsg(cli, "login")
//提示,我是谁
cli.C <- MakeMsg(cli, "I am here") isQuit := make(chan bool) //对方是否主动退出
hasData := make(chan bool) //对方是否有数据发送 //新建一个协程,接收用户发送过来的数据
go func() {
buf := make([]byte, 2048)
for {
n, err := conn.Read(buf)
if n == 0 { //对方断开,或者,出问题
isQuit <- true
fmt.Println("conn.Read err = ", err)
return
} msg := string(buf[:n-1]) //通过windows nc测试,多一个换行
if len(msg) == 3 && msg == "who" {
//遍历map,给当前用户发送所有成员
conn.Write([]byte("user list:\n"))
for _, tmp := range onlineMap {
msg = tmp.Addr + ":" + tmp.Name + "\n"
conn.Write([]byte(msg))
} } else if len(msg) >= 8 && msg[:6] == "rename" {
// rename|mike
name := strings.Split(msg, "|")[1]
cli.Name = name
onlineMap[cliAddr] = cli
conn.Write([]byte("rename ok\n")) } else {
//转发此内容
messaage <- MakeMsg(cli, msg)
} hasData <- true //代表有数据
} }() //别忘了() for {
//通过select检测channel的流动
select {
case <-isQuit:
delete(onlineMap, cliAddr) //当前用户从map移除
messaage <- MakeMsg(cli, "login out") //广播谁下线了 return
case <-hasData: case <-time.After(30 * time.Second): //60s后
delete(onlineMap, cliAddr) //当前用户从map移除
messaage <- MakeMsg(cli, "time out leave out") //广播谁下线了
return
}
}
} func main() {
//监听
listener, err := net.Listen("tcp", ":8000")
if err != nil {
fmt.Println("net.Listen err = ", err)
return
} defer listener.Close() //新开一个协程,转发消息,只要有消息来了,遍历map, 给map每个成员都发送此消息
go Manager() //主协程,循环阻塞等待用户链接
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("listener.Accept err = ", err)
continue
} go HandleConn(conn) //处理用户链接
} }

执行结果:

Go语言之进阶篇实现并发聊天功能的更多相关文章

  1. go语言之进阶篇接口转换

    1.go语音之进阶篇 示例: package main import "fmt" type Humaner interface { //子集 sayhi() } type Pers ...

  2. go语言之进阶篇并行和并发的区别与go语言并发优势

    1.并行和并发的概念 并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行. 并发(concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在 ...

  3. Go语言之进阶篇爬百度贴吧并发版

    1.爬百度贴吧并发版 示例: package main import ( "fmt" "net/http" "os" "strco ...

  4. Go语言之进阶篇简单版并发服务器

    1.简单版并发服务器 示例1: package main import ( "fmt" "net" "strings" ) //处理用户请求 ...

  5. go语言之进阶篇创建goroutine协程

    1.goroutine是什么 goroutine是Go并行设计的核心.goroutine说到底其实就是协程,但是它比线程更小,十几个goroutine可能体现在底层就是五六个线程,Go语言内部帮你实现 ...

  6. Go语言之进阶篇爬捧腹网

    1.爬捧腹网 网页规律: https://www.pengfu.com/xiaohua_1.html   下一页 +1 https://www.pengfu.com/xiaohua_2.html 主页 ...

  7. go语言之进阶篇通过select实现斐波那契数列

    一.select作用 Go里面提供了一个关键字select,通过select可以监听channel上的数据流动. select的用法与switch语言非常类似,由select开始一个新的选择块,每个选 ...

  8. go语言之进阶篇JSON处理

    一.JSON处理 JSON (JavaScript Object Notation)是一种比XML更轻量级的数据交换格式,在易于人们阅读和编写的同时,也易于程序解析和生成.尽管JSON是JavaScr ...

  9. go语言之进阶篇正则表达式

    正则表达式是一种进行模式匹配和文本操纵的复杂而又强大的工具.虽然正则表达式比纯粹的文本匹配效率低,但是它却更灵活.按照它的语法规则,随需构造出的匹配模式就能够从原始文本中筛选出几乎任何你想要得到的字符 ...

随机推荐

  1. Spring-Session实现Session共享Redis集群方式配置教程

    循序渐进,由易到难,这样才更有乐趣! 概述 本篇开始继续上一篇的内容基础上进行,本篇主要介绍Spring-Session实现配置使用Redis集群,会有两种配置方式,一种是Redis-Cluster, ...

  2. GBDT算法

    GBDT通过多轮迭代,每轮迭代产生一个弱分类器,其中弱分类器通常选择为CART树,每个分类器在上一轮分类器的残差基础上进行训练. 对于GBDT算法,其中重要的知识点为: 1.GBDT是梯度下降法从参数 ...

  3. HDU 5628 Clarke and math dp+数学

    Clarke and math 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5628 Description Clarke is a patient ...

  4. bzoj4001: [TJOI2015]概率论

    题目链接 bzoj4001: [TJOI2015]概率论 题解 生成函数+求导 设\(g(n)\)表示有\(n\)个节点的二叉树的个数,\(g(0) = 1\) 设\(f(x)\)表示\(n\)个节点 ...

  5. luoguP3175 [HAOI2015]按位或 min-max容斥 + 高维前缀和

    考虑min-max容斥 \(E[max(S)] = \sum \limits_{T \subset S} min(T)\) \(min(T)\)是可以被表示出来 即所有与\(T\)有交集的数的概率的和 ...

  6. 【HDU5909】Tree Cutting(FWT)

    [HDU5909]Tree Cutting(FWT) 题面 vjudge 题目大意: 给你一棵\(n\)个节点的树,每个节点都有一个小于\(m\)的权值 定义一棵子树的权值为所有节点的异或和,问权值为 ...

  7. NOI.AC NOIP模拟赛 第一场 补记

    NOI.AC NOIP模拟赛 第一场 补记 candy 题目大意: 有两个超市,每个超市有\(n(n\le10^5)\)个糖,每个糖\(W\)元.每颗糖有一个愉悦度,其中,第一家商店中的第\(i\)颗 ...

  8. 二叉查找树(二叉排序树)的详细实现,以及随机平衡二叉查找树Treap的分析与应用

    这是一篇两年前写的东西,自我感觉还是相当不错的Treap教程.正好期末信息科学技术概论课要求交一个论文,就把这个东西修改了一下交了,顺便也发到这里吧. 随机平衡二叉查找树Treap的分析与应用 1.序 ...

  9. bzoj 4004 向量拟阵

    题解RT. eps = 1e-10 WrongAnswer eps = 1e-5 Accepted /************************************************* ...

  10. vue 直接改变数组数据不刷新

    因为 JavaScript 的限制,Vue.js 不能检测到下面数组变化: 直接用索引设置元素,如 vm.items[0] = {}: 修改数据的长度,如 vm.items.length = 0. 为 ...