原始版本
package main
import (
"fmt"
"net"
_ "net/http"
)
//首先实现用户上线的功能,最后是用户修改自己的名字
var(
//用chan进行读取
//alladdr = make(chan net.Addr,100)
onlineMap map[string]User
//Message = make(chan map[net.Addr]User)
Message = make(chan string)//发送的消息是字符串
)
type User struct {
addr string
name string
c chan string//用户登录
c1 chan string//用户退出
}
//还有两个功能,一个是修改自己的名称
//另一个是who之后返回所有
//最后是一个定时机制,就是超过10s没有连接通信的话就踢掉
//服务器处理客户端的通信事件//需要将用户存到map里面去
func handleConnect(conn net.Conn) {
remoteAdder := conn.RemoteAddr().String()
user := User{remoteAdder,remoteAdder,make(chan string),make(chan string)}
onlineMap[remoteAdder]=user//加入用户到map中,
go connectWrite(user,conn)//这一个为什么可以触发全部的user,是每一个用户都会执行这一个协程
go logoutlisten(user,conn)
//需要将上线消息广播至全网
//用户上线,那么该用户的chan就写入数据,然后需要有全局的一个管理者一直在监听每个用户的chan
//然后从每个用户的chan中监听读,读到有消息而且是login的话就打印出来
Message<-"["+remoteAdder+"]"+"login"
go func() {
buff := make([]byte,4096)
for{
//mytime := time.NewTimer(10*time.Second)
n,err:=conn.Read(buff)//某个用户发来的消息
msg := string(buff[:n])
if n== 0{
fmt.Printf("检测到用户%s退出,关闭连接",user.name)
return
} else if err!=nil{
fmt.Println("con read err",err)
return
}else if "who\n" == msg||"who\r\n" == msg||"who" == msg{
for _,user := range onlineMap{
userinfo := user.addr+":"+user.name+"\n"
conn.Write([]byte(userinfo))
}
goto lable
}else if len(msg) >= 8 && msg[:6] == "rename"{
//替换名称
user.name = msg[8:]
onlineMap[remoteAdder] = user
conn.Write([]byte("rename success"))
return
}else if "exit" == msg{
logoutIngfo := user.name+"logout"
conn.Close()
delete(onlineMap,user.addr)
user.c1<- logoutIngfo
//不应该这么做,应该通知所有人
//需要监听
Message<- logoutIngfo
go printMessage(user,conn)
Message<- string(buff[:n])
goto lable
}else {
//将消息放入message中
//go printMessage()
go printMessage(user,conn)
Message<- string(buff[:n])
}
}
lable:
}()
}
func logoutlisten(user User,conn net.Conn) {
for{
msg :=<-user.c1
//需要将消息广播所有
go func() {
for _,v:= range onlineMap{
v.c<-msg
}
}()
}
}
func manager() {
onlineMap = make(map[string]User)
for{
msg:=<-Message
//循环向其他user的chan写入shuju
for _,v:= range onlineMap{
v.c<-msg
}
}
}
//处理由客户端发来的数据
func connectWrite(user User,conn net.Conn) {
for msg:=range user.c{
conn.Write([]byte(msg+"\n"))
}
}
func main() {
//需要tcp链接
listen, err := net.Listen("tcp","127.0.0.1:8005")
if err!=nil{
fmt.Println("net listen err",err)
}
defer listen.Close()
go manager()//创建管理者go程,管理map和全局chan
//循环监听客户端链接请求
for{
conn,err2:= listen.Accept()
if err2 !=nil{
fmt.Println("listen accept err",err2)
return
}
defer conn.Close()//某一个用户
go handleConnect(conn)
//群发消息
go handleMessage(conn)
}
}
func printMessage(user User,conn net.Conn) {
for v:=range user.c{
conn.Write([]byte(v))
}
}
func handleMessage(conn net.Conn) {
for{
//读消息,要知道读的来源是谁然后再发送至其他人,
msg:=<-Message
clientAddr:=conn.RemoteAddr().String()
//这个用户发来了消息,将消息放到每个用户的chan中
//监听接收
//需要这个client对应的用户user
//需要回归到用户
for _,v:= range onlineMap{
v.c<-"["+clientAddr+"]"+"发来数据"+":"+msg
}
}
}
修改版本
package main
import (
"fmt"
"net"
_ "net/http"
)
//首先实现用户上线的功能,最后是用户修改自己的名字
var(
//用chan进行读取
//alladdr = make(chan net.Addr,100)
onlineMap map[string]User
//Message = make(chan map[net.Addr]User)
Message = make(chan string)//发送的消息是字符串
logout = make(chan bool)
)
type User struct {
addr string
name string
c chan string//用户登录
}
//还有两个功能,一个是修改自己的名称
//另一个是who之后返回所有
//最后是一个定时机制,就是超过10s没有连接通信的话就踢掉
//服务器处理客户端的通信事件//需要将用户存到map里面去
func handleConnect(conn net.Conn) {
remoteAdder := conn.RemoteAddr().String()
user := User{remoteAdder,remoteAdder,make(chan string)}
onlineMap[remoteAdder]=user//加入用户到map中,
go connectWrite(user,conn)//这一个为什么可以触发全部的user,是每一个用户都会执行这一个协程
//需要将上线消息广播至全网
//用户上线,那么该用户的chan就写入数据,然后需要有全局的一个管理者一直在监听每个用户的chan
//然后从每个用户的chan中监听读,读到有消息而且是login的话就打印出来
Message<-"["+remoteAdder+"]"+"login"
go func() {
buff := make([]byte,4096)
for{
//mytime := time.NewTimer(10*time.Second)
n,err:=conn.Read(buff)//某个用户发来的消息
msg := string(buff[:n])
if n== 0{
logout<-true
return
} else if err!=nil{
fmt.Println("con read err",err)
return
}else if "who\n" == msg||"who\r\n" == msg||"who" == msg{
for _,user := range onlineMap{
userinfo := user.addr+":"+user.name+"\n"
conn.Write([]byte(userinfo))
}
goto lable
}else if len(msg) >= 8 && msg[:6] == "rename"{
//替换名称
user.name = msg[8:]
onlineMap[remoteAdder] = user
conn.Write([]byte("rename success"))
return
}else if "exit" == msg{
logout<-true
conn.Close()
goto lable
}else {
//将消息放入message中
//go printMessage()
go printMessage(user,conn)
Message<- string(buff[:n])
}
}
lable:
}()
for{
select {
case <-logout:
conn.Close()
delete(onlineMap,user.name)
go printMessage(user,conn)
Message<-user.name+"logout"
return
}
}
}
func manager() {
onlineMap = make(map[string]User)
for{
msg:=<-Message
//循环向其他user的chan写入shuju
for _,v:= range onlineMap{
v.c<-msg
}
}
}
//处理由客户端发来的数据
func connectWrite(user User,conn net.Conn) {
for msg:=range user.c{
conn.Write([]byte(msg+"\n"))
}
}
func main() {
//需要tcp链接
listen, err := net.Listen("tcp","127.0.0.1:8005")
if err!=nil{
fmt.Println("net listen err",err)
}
defer listen.Close()
go manager()//创建管理者go程,管理map和全局chan
//循环监听客户端链接请求
for{
conn,err2:= listen.Accept()
if err2 !=nil{
fmt.Println("listen accept err",err2)
return
}
defer conn.Close()//某一个用户
go handleConnect(conn)
//群发消息
go handleMessage(conn)
}
}
func printMessage(user User,conn net.Conn) {
for v:=range user.c{
conn.Write([]byte(v))
}
}
func handleMessage(conn net.Conn) {
for{
//读消息,要知道读的来源是谁然后再发送至其他人,
msg:=<-Message
clientAddr:=conn.RemoteAddr().String()
//这个用户发来了消息,将消息放到每个用户的chan中
//监听接收
//需要这个client对应的用户user
//需要回归到用户
for _,v:= range onlineMap{
v.c<-"["+clientAddr+"]"+"发来数据"+":"+msg
}
}
}
最终结果
package main
import (
"fmt"
"net"
_ "net/http"
"time"
)
//首先实现用户上线的功能,最后是用户修改自己的名字
//还需要开发一个超时强制踢出
var(
//用chan进行读取
//alladdr = make(chan net.Addr,100)
onlineMap map[string]User
//Message = make(chan map[net.Addr]User)
Message = make(chan string)//发送的消息是字符串
logout = make(chan bool)
alive = make(chan bool)
)
type User struct {
addr string
name string
c chan string//用户登录
}
//还有两个功能,一个是修改自己的名称
//另一个是who之后返回所有
//最后是一个定时机制,就是超过10s没有连接通信的话就踢掉
//服务器处理客户端的通信事件//需要将用户存到map里面去
func handleConnect(conn net.Conn) {
remoteAdder := conn.RemoteAddr().String()
user := User{remoteAdder,remoteAdder,make(chan string)}
onlineMap[remoteAdder]=user//加入用户到map中,
go connectWrite(user,conn)//这一个为什么可以触发全部的user,是每一个用户都会执行这一个协程
//需要将上线消息广播至全网
//用户上线,那么该用户的chan就写入数据,然后需要有全局的一个管理者一直在监听每个用户的chan
//然后从每个用户的chan中监听读,读到有消息而且是login的话就打印出来
Message<-"["+remoteAdder+"]"+"login"
go func() {
buff := make([]byte,4096)
for{
n,err:=conn.Read(buff)//某个用户发来的消息
msg := string(buff[:n])
if n== 0{
logout<-true
return
} else if err!=nil{
fmt.Println("con read err",err)
return
}else if "who\n" == msg||"who\r\n" == msg||"who" == msg{
for _,user := range onlineMap{
userinfo := user.addr+":"+user.name+"\n"
conn.Write([]byte(userinfo))
}
goto lable
}else if len(msg) >= 8 && msg[:6] == "rename" {
//替换名称
user.name = msg[8:]
onlineMap[remoteAdder] = user
conn.Write([]byte("rename success"))
return
}else {
//将消息放入message中
//go printMessage()
go printMessage(user,conn)
Message<- string(buff[:n])
}
alive<-true
}
lable:
}()
for{
select {
case <-logout:
conn.Close()
delete(onlineMap,user.name)
go printMessage(user,conn)
Message<-user.name+"logout"
return
case <-alive:
for{
;
}
case <-time.After(60*time.Second):
conn.Close()
delete(onlineMap,user.name)
go printMessage(user,conn)
Message<-user.name+"time out"
return
}
}
}
func manager() {
onlineMap = make(map[string]User)
for{
msg:=<-Message
//循环向其他user的chan写入shuju
for _,v:= range onlineMap{
v.c<-msg
}
}
}
//处理由客户端发来的数据
func connectWrite(user User,conn net.Conn) {
for msg:=range user.c{
conn.Write([]byte(msg+"\n"))
}
}
func main() {
//需要tcp链接
listen, err := net.Listen("tcp","127.0.0.1:8005")
if err!=nil{
fmt.Println("net listen err",err)
}
defer listen.Close()
go manager()//创建管理者go程,管理map和全局chan
//循环监听客户端链接请求
for{
conn,err2:= listen.Accept()
if err2 !=nil{
fmt.Println("listen accept err",err2)
return
}
defer conn.Close()//某一个用户
go handleConnect(conn)
//群发消息
go handleMessage(conn)
}
}
func printMessage(user User,conn net.Conn) {
for v:=range user.c{
conn.Write([]byte(v))
}
}
func handleMessage(conn net.Conn) {
for{
//读消息,要知道读的来源是谁然后再发送至其他人,
msg:=<-Message
clientAddr:=conn.RemoteAddr().String()
//这个用户发来了消息,将消息放到每个用户的chan中
//监听接收
//需要这个client对应的用户user
//需要回归到用户
for _,v:= range onlineMap{
v.c<-"["+clientAddr+"]"+"发来数据"+":"+msg
}
}
}