1. 程式人生 > >goland 簡單聊天室服務端

goland 簡單聊天室服務端

nag rename accept lis read 發送消息 listen ddr quit

package main

import (
	"fmt"
	"net"
	"strings"
	"time"
)

type Client struct {
	C       chan string //用於發送數據的管道
	Name    string      //用戶名
	Address string      //IP地址
}

//保存在線用戶
var onLineMap map[string]Client

var message = make(chan string)

func Manager() {
	onLineMap = make(map[string]Client)
	for {
		msg := <-message //阻塞等待消息
		for _, cli := range onLineMap {
			cli.C <- msg
		}
	}
}

//發送消息給客戶端
func WriteMessageToClient(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.Address + "]" + cli.Name + ":" + msg
	return
}

//處理用戶連接
func HandleConn(conn net.Conn) {
	defer conn.Close()
	//獲取連接客戶端網絡地址
	cliAddr := conn.RemoteAddr().String()
	//創建用戶結構體
	cli := Client{make(chan string), cliAddr, cliAddr}
	onLineMap[cliAddr] = cli

	//新建協程,發送消息給客戶端
	go WriteMessageToClient(cli, conn)
	//廣播某人在線
	message <- MakeMsg(cli, "login")
	cli.C <- MakeMsg(cli, "i am here")

	isQuit := make(chan bool)  //用戶是否主動退出
	hasData := make(chan bool) //用戶是否發送過數據
	//新建協程接收用戶發送信息
	go func() {
		buf := make([]byte, 2048)
		for {
			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 _, data := range onLineMap {
					msg = data.Address + ":" + data.Name + "\n"
					conn.Write([]byte(msg))
				}
			} else if len(msg) >= 8 && msg[:6] == "rename" {
				//修改用戶名
				cli.Name = strings.Split(msg, "|")[1]
				onLineMap[cli.Address] = cli
				conn.Write([]byte("rename success\n"))
			} else {
				//轉發消息
				message <- MakeMsg(cli, msg)
			}
			hasData <- true
		}
	}()

	for {
		select {
		case <-isQuit:
			delete(onLineMap, cli.Address) //用戶退出登錄,移除用戶
			message <- MakeMsg(cli, "login out")
			return
		case <-hasData:
		case <-time.After(60 * time.Second): //用戶60秒不操作自動超時
			delete(onLineMap, cli.Address) //用戶退出登錄,移除用戶
			message <- MakeMsg(cli, "time out leave out")
			return
		}
	}
}
func main() {
	//監聽
	listener, err := net.Listen("tcp", ":8000")
	if err != nil {
		fmt.Println("net.Listen err=", err)
		return
	}
	defer listener.Close()

	//新建一個協程,轉發消息
	go Manager()

	//主協程
	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("listener.Accept err=", err)
			continue
		}
		go HandleConn(conn) //處理用戶連接
	}
}

  

goland 簡單聊天室服務端