​go socket 实现聊天室功能​2.0(增加人员验证、监听信息、广播等功能)

​go socket 实现聊天室功能​2.0(增加人员验证、监听信息、广播等功能),第1张

前段时间用go写了一个简单的聊天室,后来考虑到任何人都可以随意加入聊天室这个问题,我就加上了一个服务端控制客户接入的功能,调整了服务端的代码。

原文章:go socket 实现聊天室功能

相比原聊天室,调整了一下几个方面:

①增加了获取客户端验证信息,控制是否允许接入聊天室。

②增加服务器监听客户端聊天记录、广播信息。

③抽取了控制管道信息输出的handleMsg方法和控制客户端输入的handleClient方法。

package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"os"
	"strings"
	"time"
)

//创建结构体存储用户名称、信息和时间
type chatMsg struct {
	name string
	msg  string
	t    string
}

var (
	msg      = make(chan string)  //用于新用户加入时广播信息
	chatMsgs = make(chan chatMsg) //发送聊天信息
	exit     = make(chan chatMsg) //离开信息
	login    = make(chan string)
	clients  = make(map[string]net.Conn) //定义一个map,使用用户名作为key,value该用户的链接
	logins   = make(map[string]net.Conn) //定义一个map,使用用户名作为key,value该用户的链接
)

func main() {
	conn, err := net.Listen("tcp", "127.0.0.0:9090") //监听本机9090端口
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("大会准备就绪,正在等待各路侠客到访...")

	go handleMsg() //开启一个线程,不断地从通道中读取数据

	for { //循环读取客户端接入
		accept, err := conn.Accept()
		if err != nil {
			log.Fatal(err)
		}

		go handleClient(accept)
	}
}

func handleMsg() {
	for {
		select {
		case chat := <-chatMsgs: //有用户发送消息
			for name, accept := range clients {
				msg := chat.t + " " + chat.name + " 说:" + chat.msg
				if name == chat.name { //当发送者是本人
					fmt.Fprintln(accept, chat.t+" 你说:"+chat.msg)
				} else {
					fmt.Fprintln(accept, msg)
				}
				fmt.Println(msg) //客户端输出用户之间的对话

			}
		case exitMsg := <-exit: //有用户离开了
			for name, accept := range clients {
				if name == exitMsg.name {
					accept.Write([]byte("exit"))
				} else {
					fmt.Fprintln(accept, "<"+exitMsg.name+exitMsg.msg+">")
				}
			}
			delete(clients, exitMsg.name)
		case m := <-msg: //上线
			for _, accept := range clients {
				fmt.Fprintln(accept, m)
			}
		}
	}
}

func handleClient(conn net.Conn) {
	//是否允许接入
	acceptEnter := false
	client := conn.RemoteAddr().String()                                          //客户端地址
	name := "无名小辈" + client[strings.LastIndex(client, ":")+1:len([]rune(client))] //使用端口号作为名称后缀
	fmt.Fprintln(conn, "正在申请加入群嘤荟,请阁下出示请帖:")
	go func() {
		for {
			loginMsg := <-login
			fmt.Println(name+"到访,拜帖信息<"+loginMsg+">", "☞输入“编号+请”允许加入", "☜输入“编号+滚”将此人赶出会场")
			loginInput := bufio.NewScanner(os.Stdin)
			acceptEnter = true
			logins[name] = conn     //将用户存入map
			for loginInput.Scan() { //循环读取客户端控制台输入内容
				text := loginInput.Text()
				if strings.HasSuffix(text, "请") {
					nameArr := strings.Split(text, "请")
					if len(nameArr) == 2 {
						key := "无名小辈" + nameArr[0]
						m := "<" + key + "已加入群嘤荟" + ">"
						clients[key] = logins[key]
						msg <- m
						fmt.Println(m)
					}
				} else if strings.HasSuffix(text, "滚") {
					nameArr := strings.Split(text, "滚")
					if len(nameArr) == 2 {
						key := "无名小辈" + nameArr[0]
						clients[key].Write([]byte("exit"))
						delete(logins, key)
						delete(clients, key)
					}
				} else {
					fmt.Fprintln(conn, "【告示】"+text)
				}
			}
		}
	}()
	go func() {//开启新的协程,判断客户端是否关闭了
		for {
			time.Sleep(time.Second)
			buf := make([]byte, 1024)
			_, err := conn.Read(buf)
			if err != nil {
				fmt.Println(name, "已悄悄离场...")
				delete(clients, name)
				break
			}
		}
	}()
	input := bufio.NewScanner(conn)
	for input.Scan() { //循环读取客户端控制台输入内容
		text := input.Text()
		if !acceptEnter { //		不允许接入,持续等待
			login <- text
			continue
		}
		if text == "exit" { //客户端输入"exit"消息时,退出聊天室
			exit <- chatMsg{name, "退出会场,青山不改绿水长流,各位有缘再见!", ""}
			break //跳出循环读取
		} else {
			t := time.Now()                                                    //获取当前时间
			chat := chatMsg{name, input.Text(), t.Format("02 Jan 2006 15:04")} //格式化时间
			chatMsgs <- chat
		}

	}
}

效果图:

 

 

 

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/994832.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存