main.go
package main
func main(){
server := NewServer("127.0.0.1", 8888)
server.Start()
}
server.go
package main
import(
"fmt"
"net"
"sync"
"io"
"time"
)
type Server struct {
Ip string
Port int
//在线用户列表
OnlineMap map[string]*User
mapLock sync.RWMutex
//消息广播channel
Message chan string
}
func NewServer(ip string,port int) *Server {
server := &Server {
Ip: ip,
Port: port,
OnlineMap: make(map[string]*User),
Message: make(chan string),
}
return server
}
//监听Message广播消息channel的goroutine,一旦有消息就发送给全部在线的User
func (this *Server) ListenMessager() {
for {
msg := <-this.Message
//发送给全部到在线User
this.mapLock.Lock()
for _, cli := range this.OnlineMap {
cli.C <- msg
}
this.mapLock.Unlock()
}
}
func (this *Server) Broadcast(user *User, msg string) {
sendMsg := "[" + user.Addr + "]" + user.Name + ":" + msg
this.Message <- sendMsg
}
func (this *Server) Handler(conn net.Conn) {
//fmt.Println("linked ok")
//用户上线了,将用户加入到onlineMap
user := NewUser(conn,this)
user.Online()
//用户是否活跃
isLive := make(chan bool)
go func() {
buf := make([]byte, 4096)
for {
n, err := conn.Read(buf)
if n==0 {
user.Offline()
return
}
if err != nil && err != io.EOF {
fmt.Println("conn read err", err)
return
}
//提取用户消息(去掉'\n')
msg := string(buf[:n-1])
//消息处理
user.DoMessage(msg)
//用户依然活跃
isLive <- true
}
}()
//当前handler阻塞
for {
select {
case <- isLive:
case <- time.After(time.Second * 300)://更新计时器
//已经超时
//强制关闭当前的User
user.SendMessage("你被踢了\n")
close(user.C)
conn.Close()
return //runtime.Goexit()
}
}
}
func (this *Server) Start() {
//socket listen
listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", this.Ip, this.Port))
if err != nil {
fmt.Println("net.listen err:", err)
return
}
//close listen socket
defer listener.Close()
//启动监听
go this.ListenMessager()
for {
//accept
conn, err := listener.Accept()
if err != nil {
fmt.Println("listener.accept err:",err)
continue
}
//do handler
go this.Handler(conn)
}
}
user.go
package main
import (
"net"
"strings"
)
type User struct {
Name string
Addr string
C chan string
conn net.Conn
server *Server
}
func NewUser(conn net.Conn, server *Server) *User {
userAddr := conn.RemoteAddr().String()
user := &User {
Name: userAddr,
Addr: userAddr,
C: make(chan string),
conn: conn,
server:server,
}
go user.ListenMessage()
return user
}
//用户上线
func (this *User) Online(){
this.server.mapLock.Lock()
this.server.OnlineMap[this.Name] = this
this.server.mapLock.Unlock()
this.server.Broadcast(this, "上线了")
}
//用户下线
func (this *User) Offline(){
this.server.mapLock.Lock()
delete(this.server.OnlineMap, this.Name)
this.server.mapLock.Unlock()
this.server.Broadcast(this, "下线了")
}
//发送消息给user
func (this *User) SendMessage(msg string){
this.conn.Write([]byte(msg))
}
//处理消息
func (this *User) DoMessage(msg string){
if msg == "who" {
//查询所有用户信息
this.server.mapLock.Lock()
for _, user := range this.server.OnlineMap {
onlineMsg := "[" + user.Addr + "]" + user.Name + ": 在线...\n"
this.SendMessage(onlineMsg)
}
this.server.mapLock.Unlock()
} else if len(msg) > 7 && msg[:7] == "rename|" {
//改名
newName := strings.Split(msg, "|")[1]
//名字是否重复
_, ok := this.server.OnlineMap[newName]
if ok {
this.SendMessage("用户名已被使用!\n")
} else {
this.server.mapLock.Lock()
delete(this.server.OnlineMap, this.Name)
this.server.OnlineMap[newName] = this
this.server.mapLock.Unlock()
}
} else if len(msg) > 4 && msg[:3] == "to|" {
//私聊功能
//1 获取对方用户名
remoteName := strings.Split(msg, "|")[1]
if remoteName == "" {
this.SendMessage("消息格式不正确!\n")
return
}
remoteUser, ok := this.server.OnlineMap[remoteName]
if !ok {
this.SendMessage("用户名不存在\n")
return
}
content := strings.Split(msg, "|")[2]
if content == "" {
this.SendMessage("空消息无法发送!\n")
return
}
remoteUser.SendMessage(this.Name + "向您发送" + content + "\n")
//2 找到对方user对象
//3 发送内容
} else {
this.server.Broadcast(this, msg)
}
}
//监听当前user的channel,有消息就写入对端客户端
func (this *User) ListenMessage(){
for{
msg := <-this.C
this.conn.Write([]byte(msg + "\n"))
}
}