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. oracle 查询 约束

    select * FROM all_constraints where CONSTRAINT_NAME='SYS_xxx'

  2. PMP 考试 形式

    200 道单选题- 考试时间为4个小时(上午9点到下午1点) 1年4次考试时间 2017年 3月18 6月24 9月9 10月9 考试费用3300 PMBOK

  3. 百度 Echart 的使用

    百度 Echarts 的使用 一.Echarts 简介 官方网站:http://echarts.baidu.com/ 下载地址:http://echarts.baidu.com/download.ht ...

  4. BZOJ3772精神污染

    参见http://blog.csdn.net/popoqqq/article/details/43122821 #include<bits/stdc++.h> using namespac ...

  5. 8.4 正睿暑期集训营 Day1

    目录 2018.8.4 正睿暑期集训营 Day1 A 数对子 B 逆序对 C 盖房子 考试代码 A B C 2018.8.4 正睿暑期集训营 Day1 时间:4.5h(实际) 期望得分:30+50+3 ...

  6. 【原】Spring整合Redis(第二篇)—SDR环境搭建具体步骤

    [环境参数] Spring版本:4.2.6.RELEASESpring-Data-Redis版本:1.7.2.RELEASE Redis版本:redis-2.4.5-win32-win64 [简要说明 ...

  7. linux 内核升级2 转

    linux内核升级 一.Linux内核概览 Linux是一个一体化内核(monolithic kernel)系统. 设备驱动程序可以完全访问硬件. Linux内的设备驱动程序可以方便地以模块化(mod ...

  8. .Net Discovery 系列之五--深入浅出.Net实时编译机制(上)

    欢迎阅读“.Net Discovery 系列”文章,本文将分上.下两部分为大家讲解.Net JIT方面的知识,敬请雅正. JIT(Just In Time简称JIT)是.Net边运行边编译的一种机制, ...

  9. WSAEventSelect模型编程 详解

    转自:http://blog.csdn.net/wangjieest/article/details/7042108 WSAEventSelect模型编程 WSAEventSelect模型编程这个模型 ...

  10. springcloud 分布式服务跟踪sleuth+zipkin

    原文:https://www.jianshu.com/p/6ef0b76b9c26 分布式服务跟踪需求 随着分布式服务越来越多,调用关系越来越复杂,组合接口越来越多,要进行分布式服务跟踪监控的需求也越 ...