package main

import (
"net"
"fmt"
"strings"
"time"
) type Client struct {
C chan string //用户发送数据的通道
Name string //用户名
Addr string //网络地址
} //保存在线用户 cliaddr ======> client
var onlineMap map[string]Client var message = make(chan string) 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 + ": login"
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) //广播某个人在线
message <- MakeMsg(cli, "login") //提示,我是谁
cli.C <- MakeMsg(cli, "I am here") var isQuit = make(chan bool) hasData := make(chan bool) go func() {
buf := make([]byte, 2048)
for true {
n, err := conn.Read(buf)
if n == 0 { //对方断开,或者出问题
isQuit <- true
fmt.Println("conn.read err = ", err)
return
}
msg := string(buf[:n-1])
if len(msg) == 3 && msg == "who" {
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("user list :\n"))
}else {
message <- MakeMsg(cli, msg)
}
}
}() for true {
select {
case <- isQuit:
delete(onlineMap, cliAddr) //当前用户从map移除
message <- MakeMsg(cli, "log out") //广播谁下线了
return
case <- hasData:
//不做操作
case time.After(60*time.Second): //60秒都没有操作了,超时
delete(onlineMap, cliAddr) //当前用户从map移除
message <- MakeMsg(cli, "tiem out") //广播谁下线了
return
}
}
} func Manager() {
//给map分配空间map
onlineMap = make(map[string]Client) for true {
msg := <-message //没有消息前,这里会阻塞
//遍历map,给map每个成员都发送此消息
for _, cli := range onlineMap{
cli.C <- msg
}
} } func main() {
//创建监听
listener, err := net.Listen("tcp", ":8000")
if err != nil {
fmt.Println("net.Listen err = ", err)
return
} //新开一个协程,用于转发消息,只要有消息到达 ,那就遍历map然后给map每个成员都发送消息
go Manager() //主协程,循环阻塞等待用户连接
for true {
conn, err := listener.Accept()
if err != nil {
fmt.Println("listener.Accept err = ", err)
continue //如果这个不发,説不定还有下个发呢
}
//处理用户的连接
go HandleConn(conn)
}
}

执行的结果,当有任何一个新用户登录了,其他所有的用户都会收到登录提醒,这里以ip加端口号的试做为一个唯一标识

[GO]并发实现聊天室服务器的更多相关文章

  1. Python Socket 编程——聊天室示例程序

    上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和客户端的代码了解基本的 Python Socket 编程模型.本文再通过一个例子来加强一下对 Socket 编程的 ...

  2. Linux聊天室项目 -- ChatRome(select实现)

    序 项目简介:采用I/O复用技术select实现socket通信,采用多线程负责每个客户操作处理,完成Linux下的多客户聊天室! OS:Ubuntu 15.04 IDE:vim gcc make D ...

  3. 基于LINUX的多功能聊天室

    原文:基于LINUX的多功能聊天室 基于LINUX的多功能聊天室 其实这个项目在我电脑已经躺了多时,最初写完项目规划后,我就认认真真地去实现了它,后来拿着这个项目区参加了面试,同样面试官也拿这个项目来 ...

  4. 【C】——网络编程-聊天室

    功能介绍: 此demo是基于TCP套接字编程,目的是实现一个聊天室效果.类似于QQ群效果,如果上线可以通知其他好友,下线也会通知其他好友. 需要用的技术: 一.socket编程. 1> sock ...

  5. Netty网络聊天室之会话管理

    写过web的同学们应该对Session这个东西很熟悉.浏览器第一次与服务器建立连接的时候,服务器就会自动为之分配一个Session.Session可以用来判断用户是否经过登录验证,也可以保存用户的各种 ...

  6. ASP.NET SingalR + MongoDB 实现简单聊天室(三):实现用户群聊,总结完善

    前两篇已经介绍的差不多了,本篇就作为收尾. 使用hub方法初始化聊天室的基本步骤和注意事项 首先确保页面已经引用了jquery和singalR.js还有对应的hubs文件,注意,MVC框架有时会将jq ...

  7. 基于EPOLL模型的局域网聊天室和Echo服务器

    一.EPOLL的优点 在Linux中,select/poll/epoll是I/O多路复用的三种方式,epoll是Linux系统上独有的高效率I/O多路复用方式,区别于select/poll.先说sel ...

  8. 利用html 5 websocket做个山寨版web聊天室(手写C#服务器)

    在之前的博客中提到过看到html5 的websocket后很感兴趣,终于可以摆脱长轮询(websocket之前的实现方式可以看看Developer Works上的一篇文章,有简单提到,同时也说了web ...

  9. ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(二) 之 ChatServer搭建,连接服务器,以及注意事项。

    上篇:ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(一) 之 基层数据搭建,让数据活起来(数据获取) 上一篇我们已经完成了初步界面的搭建工作,本篇将介绍IM的核心内容 ...

随机推荐

  1. 多分类下的ROC曲线和AUC

    本文主要介绍一下多分类下的ROC曲线绘制和AUC计算,并以鸢尾花数据为例,简单用python进行一下说明.如果对ROC和AUC二分类下的概念不是很了解,可以先参考下这篇文章:http://blog.c ...

  2. 操作系统-百科:Linux

    ylbtech-操作系统-百科:Linux Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU的操作系统.它能运行主要的UNI ...

  3. Maven的学习

    Maven是Apache的一个项目,它使用对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具.它集项目的构建,清理,编译等于一体,以前我们在使用IDE时,基本上一 ...

  4. url携带的参数获取并处理demo

    url demo: http://servername/webname/pagename.csp?paramName=paramValue&paramName2=paramName2& ...

  5. nginx+php产生大量TIME_WAIT连接解决办法

    问题:当启动nginx和php-fpm时,使用netstat -tunap查看到大量TIME_WAIT连接 由于不知道原因,害怕是受到攻击,马上killall nginx 和php-fpm 会不会是8 ...

  6. bat执行sqlplus语句,省去@xx.sql过程

    bat文件中执行写sqlplus连接,再@调用自己,sql登录成功后,会忽略掉第一行sqlplus xxx,转而执行下方的sql语句 --------------------------------- ...

  7. 象棋AI算法(二)

    原文大神是用html5+js写的关于象棋AI的博客,里面重点讲了棋子的着法,自己设计的评估函数和简单的Minmax理论,没有具体的讲搜索算法,本文是对原文的学习和分析补充 一,棋子的着法com.byl ...

  8. html——网页高度

    确定浏览器窗口的尺寸(浏览器的视口,不包括工具栏和滚动条) var w=window.innerWidth || document.documentElement.clientWidth || doc ...

  9. 基于 DirectX11 的 MMDViewer 03-渲染管线

    准备工作: 开始搭建框架之前,你需要确保已经进行了 D3D 开发环境的搭建,相关教程可以阅读这篇文章.不了解 DirectX11 的人,这个作者有关 DirectX11 的教程最好阅读一下,虽然文章不 ...

  10. JBPM4.4学习笔记

    1.JBPM4表说明: JBPM4_DEPLOYMENT 流程定义表 JBPM4_DEPLOYPROP 流程定义属性表 JBPM4_EXECUTION 流程实例表 JBPM4_HIST_ACTINST ...