github.com/gin-gonic/gin github.com/gorilla/websocket
package ws import ( "encoding/json" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" "log" "net/http" ) // ClientManager is a websocket manager type ClientManager struct { Clients map[string]*Client Broadcast chan []byte Register chan *Client Unregister chan *Client } // Client is a websocket client type Client struct { ID string Socket *websocket.Conn Send chan []byte } // Message is return msg type Message struct { Sender string `json:"sender,omitempty"` Recipient string `json:"recipient,omitempty"` Content string `json:"content,omitempty"` } // Manager define a ws server manager var Manager = ClientManager{ Broadcast: make(chan []byte), Register: make(chan *Client), Unregister: make(chan *Client), Clients: make(map[string]*Client), } // Start is 項目運行前, 協程開啓start -> go Manager.Start() func (manager *ClientManager) Start() { for { log.Println("<---管道通訊--->") select { case conn := <-Manager.Register: log.Printf("新用戶加入:%v", conn.ID) Manager.Clients[conn.ID] = conn jsonMessage, _ := json.Marshal(&Message{Content: "Successful connection to socket service"}) conn.Send <- jsonMessage case conn := <-Manager.Unregister: log.Printf("用戶離開:%v", conn.ID) if _, ok := Manager.Clients[conn.ID]; ok { jsonMessage, _ := json.Marshal(&Message{Content: "A socket has disconnected"}) conn.Send <- jsonMessage close(conn.Send) delete(Manager.Clients, conn.ID) } case message := <-Manager.Broadcast: MessageStruct :=Message{} json.Unmarshal(message, &MessageStruct) for id, conn := range Manager.Clients { if id!=creatId(MessageStruct.Recipient,MessageStruct.Sender){ continue } select { case conn.Send <- message: default: close(conn.Send) delete(Manager.Clients, conn.ID) } } } } } func creatId(uid,touid string) string { return uid+"_"+touid } func (c *Client) Read() { defer func() { Manager.Unregister <- c c.Socket.Close() }() for { c.Socket.PongHandler() _, message, err := c.Socket.ReadMessage() if err != nil { Manager.Unregister <- c c.Socket.Close() break } log.Printf("讀取到客戶端的信息:%s", string(message)) Manager.Broadcast <- message } } func (c *Client) Write() { defer func() { c.Socket.Close() }() for { select { case message, ok := <-c.Send: if !ok { c.Socket.WriteMessage(websocket.CloseMessage, []byte{}) return } log.Printf("發送到到客戶端的信息:%s", string(message)) c.Socket.WriteMessage(websocket.TextMessage, message) } } } //TestHandler socket 鏈接 中間件 做用:升級協議,用戶驗證,自定義信息等 func WsHandler(c *gin.Context) { uid := c.Query("uid") touid := c.Query("to_uid") conn, err := (&websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}).Upgrade(c.Writer, c.Request, nil) if err != nil { http.NotFound(c.Writer, c.Request) return } //能夠添加用戶信息驗證 client := &Client{ ID: creatId(uid,touid), Socket: conn, Send: make(chan []byte), } Manager.Register <- client go client.Read() go client.Write() }
package main import ( "github.com/gin-gonic/gin" "im/ws" ) //server func main() { gin.SetMode(gin.ReleaseMode) //線上環境 go ws.Manager.Start() r := gin.Default() r.GET("/ws",ws.WsHandler) r.GET("/pong", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "pong", }) }) r.Run(":8282") // listen and serve on 0.0.0.0:8080 }
go run mian.go
<html> <head> <title>Golang Chat</title> <script src="http://libs.baidu.com/jquery/1.4.2/jquery.min.js"></script> <meta charset="UTF-8" /> <script type="text/javascript"> $(function() { function getUrlParam(name) { var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)"); //構造一個含有目標參數的正則表達式對象 var r = window.location.search.substr(1).match(reg); //匹配目標參數 if (r!=null) return unescape(r[2]); return null; //返回參數值 } var conn; var msg = $("#msg"); var log = $("#log"); uid=getUrlParam("uid"); to_uid=getUrlParam("to_uid"); function appendLog(msg) { var d = log[0] var doScroll = d.scrollTop == d.scrollHeight - d.clientHeight; msg.appendTo(log) if (doScroll) { d.scrollTop = d.scrollHeight - d.clientHeight; } } $("#form").submit(function() { if (!conn) { return false; } if (!msg.val()) { return false; } var json = {"sender":uid,"recipient":to_uid,"content":msg.val()}; //建立對象; var jsonStr = JSON.stringify(json); //轉爲JSON字符串 conn.send(jsonStr); msg.val(""); return false }); if (window["WebSocket"]) { conn = new WebSocket("ws://localhost:8282/ws?uid="+uid+"&to_uid="+to_uid); conn.onclose = function(evt) { appendLog($("<div><b>Connection Closed.</b></div>")) } conn.onmessage = function(evt) { appendLog($("<div/>").text(evt.data)) } } else { appendLog($("<div><b>WebSockets Not Support.</b></div>")) } }); </script> <style type="text/css"> html { overflow: hidden; } body { overflow: hidden; padding: 0; margin: 0; width: 100%; height: 100%; background: gray; } #log { background: white; margin: 0; padding: 0.5em 0.5em 0.5em 0.5em; position: absolute; top: 0.5em; left: 0.5em; right: 0.5em; bottom: 3em; overflow: auto; } #form { padding: 0 0.5em 0 0.5em; margin: 0; position: absolute; bottom: 1em; left: 0px; width: 100%; overflow: hidden; } </style> </head> <body> <div id="log"></div> <form id="form"> <input type="submit" value="發送" /> <input type="text" id="msg" size="64"/> </form> </body> </html>
本身搭建nginx或apache等web服務,分別在兩個窗口運行javascript
http://localhost/client.html?...css
http://localhost/client.html?...html
這樣就能夠聊天了java