go聊天室

首先需要下载安装websocket

  • cmd中:go get -u -v github.com/gorilla/websocket

首先在连接中传输的数据抽象出对象,这些对象在接下来都会用到

type Data struct{
	Ip string `json:"ip"`
	Type string `json:"type"`
	// 代表哪个用户说的
	From string `json:"from"`
//	传输内容
	Content string `json:"content"`
//	用户名
	User string `json:"user"`
//	用户列表
	UserList []string `json:"user_list"`
}

创建一个ws连接器,这里需要创建一个websocket的链接,便于从后台导出数据

type connection struct {
	// ws连接器
	ws *websocket.Conn
	//管道
	send chan []byte
	//数据
	data *Data
}

接着创建一个hub,hub主要处理ws中的各种逻辑

type hub struct {
	// connnections注册了连接器
	connections map[*connection]bool
	//从连接器发送的信息
	broadcast chan []byte
	// 从连接器注册请求
	register chan *connection
	//销毁请求
	unregister chan *connection
}

创建了对象之后,就需要将连接器对象进行初始化

var h = hub{
	//connections 注册了连接器
	connections: make(map[*connection]bool),
	//从连接器发送的信息
	broadcast: make(chan []byte),
	//从连接器注册请求
	register: make(chan *connection),
	//销毁请求
	unregister: make(chan *connection),
}

创建一个字符串切片,存用户名

// 用户列表
var user_list = []string{}

ws的主要作用就是实现读和写,接下来就需要先实现ws的读和写

//ws中写数据
//这里必须要知道是谁写的,所以将connection绑定在这里
func (c *connection)writer(){
	//从管道遍历数据
	for message := range c.send{
		// 数据写出
		c.ws.WriteMessage(websocket.TextMessage,message)
	}
	c.ws.Close()
}
//ws连接中读数据
func (c *connection) reader(){
	//创建一个死循环 ,不断地读数据
	for{
		_,message,err := c.ws.ReadMessage()
		if err != nil{
			// 读不进数据,将用户移除
			h.unregister <- c
			break
		}
		// 读取数据
		json.Unmarshal(message,&c.data)
		//根据data 的type判断该做什么,根据不同的数据类型,进行不同的处理
		switch c.data.Type{
		case "login":
			// 弹出窗口
			c.data.User = c.data.Content
			c.data.From = c.data.User
			//登录后
			user_list = append(user_list,c.data.User)
			//每个用户都加在所有登录的列表
			c.data.UserList = user_list
			// 数据序列化
			data_b, _ := json.Marshal(c.data)
			h.broadcast <- data_b
			// 普通状态
		case "user":
			c.data.Type = "user"
			data_b ,_ := json.Marshal(c.data)
			h.broadcast <- data_b
		case "logout":
			//当用户退出时,就需要删除用户数据
		default:
			fmt.Println("其他")
		}
	}
}

当用户退出时,我们需要删除用户切片中的数据,所以就需要创建一个函数来删除数据

//删除用户切片中数据
func remove(slice []string,user string) []string{
	// 严谨判断
	count := len(slice)
	if count == 0{
		return slice
	}
	if count == 1 && slice[0] == user{
		return []string{}
	}
	//定义新的返回切片
	var my_slice = []string{}
	//删除传入切片中的指定用户,其他用户放到新的切片
	for i := range slice{
		// 利用索引删用户
		if slice[i] == user && i == count{
			return slice[:count]
		}else if slice[i] == user {
			my_slice = append(slice[:i],slice[i+1:]...)
			break
		}
	}
	return my_slice
}

logout部分代码:

c.data.Type = "logout"
// 用户列表删除
user_list = remove(user_list,c.data.User)
c.data.UserList = user_list
c.data.Content = c.data.User
// 数据序列化,让所有人看到xxx下线了
data_b,_ := json.Marshal(c.data)
h.broadcast <- data_b
h.unregister <- c

先定义一个升级器,将http请求升级成websocket请求

var upgrader = &websocket.Upgrader{ReadBufferSize:1024,WriteBufferSize:1024,
	CheckOrigin: func(r *http.Request) bool{
		return true
	}}

最终写主函数的时候,需要一个回调函数,主要写ws应该做什么事,这里的参数主要是进行请求和响应的

func wsHandler(w http.ResponseWriter, r *http.Request){
	// 获取ws对象
	ws,err := upgrader.Upgrader(w,r,nil)
	if err != nil{
		return
	}
	//创建连接诶额对象去做事情
	// 初始化链接对象
	c := &connection{send:make(chan[]byte,128),ws:ws,data:&Data{}}
	// 在ws 中注册一下
	h.register <- c
	//ws将数据读写跑起来
	go c.writer()
	c.reader()
	defer func(){
		c.data.Type = "logout"
		// 用户列表删除
		user_list = remove(user_list,c.data.User)
		c.data.UserList = user_list
		c.data.Content = c.data.User
		// 数据序列化,让所有人看到xxx下线了
		data_b,_ := json.Marshal(c.data)
		h.broadcast <- data_b
		h.unregister <- c
	}()
}

接着处理一下ws的逻辑实现

func (h *hub) run(){
	//监听数据管道,在后端不断处理管道数据
	for{
		// 根据不同的数据管道,处理不同的逻辑
		select {
		// 注册
		case c := <- h.register:
			//标志注册了
			h.connections[c] = true
			// 组装data数据
			c.data.Ip = c.ws.RemoteAddr().String()
			// 更新类型
			c.data.Type = "handshake"
			// 用户列表
			c.data.UserList = user_list
			data_b, _ := json.Marshal(c.data)
			//将数据放入数据管道
			c.send <- data_b
		case c := <- h.unregister:
			//判断map里存在要删除的数据
			if _,ok := h.connections[c]; ok{
				delete(h.connections,c)
				close(c.send)
			}
		case data := <- h.broadcast:
			//处理数据流转,将数据同步到所有用户
			// c是具体的每一个连接
			for c := range h.connections{
				// 将数据同步
				select {
					case c.send <- data:
				default:
					//防止死循环
					delete(h.connections,c)
					close(c.send)
				}
			}
		}
	}

接着就是创建一个主函数

func main() {
	//创建路由
	router := mux.NewRouter()
	// ws控制器不断地去处理管道数据,进行同步数据
	go h.run()
	//指定ws回调函数
	router.HandleFunc("/ws",wsHandler)
	// 开启服务器监听
	if err := http.ListenAndServe("127.0.0.1:8080",router);err != nil{
		fmt.Println("err:", err)
	}
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值