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. js手机号正则表达式验证

    var phone = $("#phone").val(); //陈旧版 var parphone = /^(((13[0-9]{1})|(17[0-9]{1})|(15[0-9] ...

  2. Maven assembly插件进行自定义构建

    众所周知,Maven是一个约定优于配置的java构建工具,通常我们只需要定义非常少的内容,就可以根据package标签属性来构建生成的jar, war包的相关内容. 如果想要对maven中依赖的内容一 ...

  3. 【BZOJ】1007: [HNOI2008]水平可见直线(凸包)

    题目 传送门:QWQ 分析 在下面维护一个凸壳 好久没写博客了...... 代码 #include <bits/stdc++.h> using namespace std; ; ,INF= ...

  4. 【UVa】1600 Patrol Robot(dfs)

    题目 题目     分析 bfs可以搞,但是我还是喜欢dfs,要记忆化不然会T     代码 #include <cstdio> #include <cstring> #inc ...

  5. Python - Pyinstaller

    安装 Pyinstaller pip install pyinstaller 使用: test.py print("Hello World!") 命令行输入 pyinstaller ...

  6. 第六章:Reminders实验:第二部分[Learn Android Studio 汉化教程]

    Learn Android Studio 汉化教程 Reminders Lab: Part 2 This chapter covers capturing user input through the ...

  7. Java EE学习路线

    题记: 不行动,注定是个失败者! 1.coding:servlet->jsp 通过看视频快速上手 2.reading:Thinking in java 英文版 时间协调安排: 1.上课时认真听课 ...

  8. Python Web框架——Django

    返回顶部 使用框架简单快速开发特定的系统. pip freeze > requirements.txt pip install -r requirements.txt 一 MVC和MTV模式 二 ...

  9. c++builder 画图 填充

    c++builder 画图 填充 void __fastcall TForm2::Button1Click(TObject *Sender) { Canvas->Brush->Color ...

  10. 运维自动化工具 Cobbler

    简介: 关于操作系统安装方面的自动化,早前我们使用 RedHat 推出的 Kickstart 来批量安装操作系统,近年来 RedHat 又推出一个 Cobbler . Cobbler 使用 Pytho ...