**经过几天奋战,终于学习了gorilla的基本聊天功能,以及对channel简单的理解:**
**请求URL:**
- ` web:localhost:3000 `
- ` websocket:localhost:3000/ws `
**第一个示例**
- ` 这个示例简单的实现了websocket功能,那么我该如何实现聊天功能呢? 看了官网gorilla的chat例子,看了几天头疼,因为面向对象的思想和单进场思想让我对go的这种语法一头雾水,经过几天慢慢体会到了go的一些深意。如何通过channel实现并行,多个channel如何实现。`
```
package main
import (
"net/http"
"time"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{}
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "index.html")
})
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
// 客户端连接链接
var conn, _ = upgrader.Upgrade(w, r, nil)
go func(conn *websocket.Conn) {
for {
// 读取用户信息
_, msg, _ := conn.ReadMessage()
// 发送用户信息
conn.WriteJSON("{'user':'" + string(msg) + "'}")
}
}(conn)
})
http.ListenAndServe(":3000", nil)
}
```
**第二个示例**
```
package main
import (
"fmt"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{}
type Hub struct {
clients map[*Client]bool // *Client
addClient chan *Client
}
var hub = Hub{
clients: make(map[*Client]bool),
addClient: make(chan *Client),
}
func (hub *Hub) start() {
fmt.Println("123")
for {
select {
// 读取入channel中的数据(1channel)
case conn := <-hub.addClient:
hub.clients[conn] = true // 保存客户端连接到map中,这样我就可以实现客户a发送来的信息通过循环这个map发送到其他的客户端
fmt.Println(hub.clients)
}
}
}
type Client struct {
ws *websocket.Conn
}
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "index.html")
})
// 首先main函数走到这里,将数据保存全局变量里面
go hub.start()
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
// 创建客户端连接
var conn, _ = upgrader.Upgrade(w, r, nil)
// 将客户端conn保存在strcut中,为什么要保存在strcut中,也可以不用保存在struct中,为了方便,理解一下struct
client := &Client{ws: conn}
// 将client写入channel中, 然后保存在map中(1channe)
hub.addClient <- client
// 但是这里还是没有实现将消息分发到其他客户端,那么我们改怎么办呢?
// 我们可以【_, msg, _ := conn.ReadMessage()】读取到的消息(msg变量)写入在channel中,然后通过goruntine方式读取出来
go func(conn *websocket.Conn) {
for {
// 读取用户信息
_, msg, _ := conn.ReadMessage()
// 发送用户信息
conn.WriteJSON("{'user':'" + string(msg) + "'}")
}
}(conn)
})
http.ListenAndServe(":3000", nil)
}
```
**第三个示例**
```
package main
import (
"fmt"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{}
type Hub struct {
clients map[*Client]bool
addClient chan *Client
msg chan []byte
}
var hub = Hub{
clients: make(map[*Client]bool),
addClient: make(chan *Client),
msg: make(chan []byte),
}
func (hub *Hub) start() {
fmt.Println("123")
for {
select {
// 读取入channel中的数据(1channel)
case conn := <-hub.addClient:
hub.clients[conn] = true // 保存map
fmt.Println(hub.clients)
// 读取channel中的数据,这里是获取用户发送的数据(2channel)
case msg := <-hub.msg:
// 这里循环map里面保存的客户端连接信息
for k, _ := range hub.clients {
//发送消息到每一个连接的客户端
k.ws.WriteMessage(1, msg)
}
}
}
}
type Client struct {
ws *websocket.Conn
}
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "index.html")
})
// 首先main函数走到这里,将数据保存全局变量里面
go hub.start()
http.HandleFunc("/v1/ws", func(w http.ResponseWriter, r *http.Request) {
// 创建客户端连接
var conn, _ = upgrader.Upgrade(w, r, nil)
client := &Client{ws: conn}
// 将client写入channel中(1channe)
hub.addClient <- client
// 这里获取客户端发送来的消息
go func(conn *websocket.Conn) {
for {
_, msg, _ := conn.ReadMessage()
//将msg保存在channel中(2channel)
hub.msg <- msg
}
}(conn)
})
http.ListenAndServe(":3000", nil)
}
```
** html代码 **
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<input type="text" placeholder="message" id="textbox">
<button id="button">Send</button>
<div id="box"></div>
<script>
var socket = new WebSocket("ws://localhost:3000/ws");
var button = document.getElementById("button");
button.addEventListener("click", function(event){
var text = document.getElementById("textbox").value;
socket.send(text);
});
socket.onopen = function(event){
console.log("Socket opened successfully");
}
socket.onmessage = function(event){
var box = document.createElement("div");
box.innerHTML = event.data;
document.getElementById("box").appendChild(box);
}
window.onbeforeunload = function(event){
socket.close();
}
</script>
</body>
</html>
```
**备注**
- 到这里就简单的实现了聊天功能,这里有一个问题需要学者自己去实现以下,当关闭一个客户端的时候这个程序会崩溃退出,也就是如何将map中保存的客户端删除功能,我相信你行,因为我都行哈哈,初出茅庐求喷!谢谢,祝大家生活愉快!
有疑问加站长微信联系(非本文作者)