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