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"))
	}
}