go-----简单聊天室

go-----简单聊天室

直接上代码

	package main

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

	//创建用户结构体类型
	type Cline struct {
		C    chan string
		Name string
		Addr string
	}

	//创建全局map,存储在线用户
	var onlineMap map[string]Cline

	//创建全局 channel 传递用户消息
	var message = make(chan string)

	func WriteToConnect(clnt Cline, conn net.Conn) {
		//监听用户自带Channel上是否有消息
		for msg := range clnt.C {
			conn.Write([]byte(msg + "\n"))
		}

	}

	func MakeMsg(clnt Cline, msg string) (buf string) {
		buf = "[" + clnt.Addr + "]" + clnt.Name + ": " + msg
		return
	}

	func HandlerConnect(conn net.Conn) {
		defer conn.Close()
		//创建channel判断用户是否活跃
		hasData := make(chan bool)
		//创建新链接用户的信息 结构体  默认用户名是IP+port
		netAddr := conn.RemoteAddr().String()
		clnt := Cline{C: make(chan string), Name: netAddr, Addr: netAddr}

		//将新连接用户添加到在线用户map中,key:IP+port
		onlineMap[netAddr] = clnt

		//创建专门给当前用户发送消息的go程
		go WriteToConnect(clnt, conn)
		//发送用户上线消息到全局channel中
		message <- MakeMsg(clnt, "login")
		//创建一个channel,用来判断推出状态
		isQuit := make(chan bool)
		//创建一个go程,专门处理用户发出的消息
		go func() {
			buf := make([]byte, 4096)
			for {
				n, err := conn.Read(buf)
				if n == 0 {
					isQuit <- true
					fmt.Println("检测到客户端:%s退出 \n", clnt.Name)
				}
				if err != nil {
					fmt.Println("conn.Read err: ", err)
					return
				}

				msg := string(buf[:n-1])
				//提取在线用户列表
				if msg == "who" && len(msg) == 3 {
					conn.Write([]byte("online user list :\n"))
					//遍历当前map,获取在线用户
					for _, user := range onlineMap {
						userInfo := user.Addr + ":" + user.Name + "\n"
						conn.Write([]byte(userInfo))
					}
				} else if len(msg) >= 8 && msg[:6] == "rename" { //判断用户发送了改名命令
					newName := strings.Split(msg, "|")[1]
					clnt.Name = newName
					onlineMap[netAddr] = clnt
					conn.Write([]byte("Rename successful\n"))
				} else {
					//将读到的用户消息,写入到message中,
					message <- MakeMsg(clnt, msg)
				}
				hasData <- true
			}
		}()

		for {
			select {
			case <-isQuit:
				close(clnt.C)
				//将用户从在线用户列表移除
				delete(onlineMap, clnt.Addr)
				message <- MakeMsg(clnt, "logout") //写入用户退出消息到全局channel
				return
			case <-hasData:
				//什么都不做,目的是充值下面case的计时器。
			case <-time.After(time.Second * 10):
				//将用户从在线用户列表移除
				delete(onlineMap, clnt.Addr)
				message <- MakeMsg(clnt, "logout") //写入用户退出消息到全局channel
				return
			}
		}

	}

	func Manager() {
		//初始化map
		onlineMap = make(map[string]Cline)

		for { //监听全局channel中是否有数据,有数据存储至msg,无数据阻塞。
			msg := <-message
			//循环发送消息给所有在新用户
			for _, clnt := range onlineMap {
				clnt.C <- msg
			}
		}

	}

	func main() {
		//创建监听套接字
		listener, err := net.Listen("tcp", "127.0.0.1:8000")
		if err != nil {
			fmt.Println("Listener err", err)
			return
		}
		defer listener.Close()
		//创建管理者go程,管理map和全局channel
		go Manager()
		//循环坚挺客户端连接请求
		for {
			conn, err := listener.Accept()
			if err != nil {
				fmt.Println("Accept err ", err)
				return
			}
			//启动go程处理客户端数据请求
			go HandlerConnect(conn)
		}
	}

运行

	//运行服务
	go run main.go
	//运行客户端
	nc 127.0.0.1 8000
	//更改用户名
	rename|newname
	//用户列表
	who
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值