先安装依赖包:

  1. go get github.com/gorilla/websocket

server.go

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. "github.com/gorilla/websocket"
  7. "github.com/satori/go.uuid"
  8. )
  9. type ClientManager struct {
  10. clients map[*Client]bool
  11. broadcast chan []byte
  12. register chan *Client
  13. unRegister chan *Client
  14. }
  15. type Client struct {
  16. id string
  17. socket *websocket.Conn
  18. send chan []byte
  19. }
  20. type Message struct {
  21. Sender string `json:"sender,omitempty"`
  22. Recipient string `json:"recipient,omitempty"`
  23. Content string `json:"content,omitempty"`
  24. }
  25. var manager = ClientManager{
  26. broadcast: make(chan []byte),
  27. register: make(chan *Client),
  28. unRegister: make(chan *Client),
  29. clients: make(map[*Client]bool),
  30. }
  31. func (manager *ClientManager) start() {
  32. for {
  33. select {
  34. case conn := <-manager.register:
  35. manager.clients[conn] = true
  36. jsonMessage, _ := json.Marshal(&Message{Content: conn.id + "/A new socket has connected."})
  37. manager.send(jsonMessage, conn)
  38. case conn := <-manager.unRegister:
  39. if _, ok := manager.clients[conn]; ok {
  40. close(conn.send)
  41. delete(manager.clients, conn)
  42. jsonMessage, _ := json.Marshal(&Message{Content: conn.id + "/A socket has disconnected."})
  43. manager.send(jsonMessage, conn)
  44. }
  45. case message := <-manager.broadcast:
  46. for conn := range manager.clients {
  47. select {
  48. case conn.send <- message:
  49. default:
  50. close(conn.send)
  51. delete(manager.clients, conn)
  52. }
  53. }
  54. }
  55. }
  56. }
  57. func (manager *ClientManager) send(message []byte, ignore *Client) {
  58. for conn := range manager.clients {
  59. if conn != ignore {
  60. conn.send <- message
  61. }
  62. }
  63. }
  64. func (c *Client) read() {
  65. defer func() {
  66. manager.unRegister <- c
  67. c.socket.Close()
  68. }()
  69. for {
  70. _, message, err := c.socket.ReadMessage()
  71. if err != nil {
  72. manager.unRegister <- c
  73. c.socket.Close()
  74. break
  75. }
  76. var content map[string]string
  77. json.Unmarshal(message, &content)
  78. if user, ok := content["user"]; ok {
  79. fmt.Print(user)
  80. }
  81. jsonMessage, _ := json.Marshal(&Message{Sender: c.id, Content: string(message)})
  82. manager.broadcast <- jsonMessage
  83. }
  84. }
  85. func (c *Client) write() {
  86. defer func() {
  87. c.socket.Close()
  88. }()
  89. for {
  90. select {
  91. case message, ok := <-c.send:
  92. if !ok {
  93. c.socket.WriteMessage(websocket.CloseMessage, []byte{})
  94. return
  95. }
  96. c.socket.WriteMessage(websocket.TextMessage, message)
  97. }
  98. }
  99. }
  100. func main() {
  101. fmt.Println("Starting application...")
  102. go manager.start()
  103. http.HandleFunc("/ws", wsPage)
  104. http.ListenAndServe(":8081", nil)
  105. }
  106. func wsPage(res http.ResponseWriter, req *http.Request) {
  107. u := &websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}
  108. conn, err := u.Upgrade(res, req, nil)
  109. if err != nil {
  110. http.NotFound(res, req)
  111. return
  112. }
  113. newUUID, err := uuid.NewV4()
  114. if err != nil {
  115. http.Error(res, "generate uuid error, please try again!", 900)
  116. return
  117. }
  118. client := &Client{id: newUUID.String(), socket: conn, send: make(chan []byte)}
  119. manager.register <- client
  120. go client.read()
  121. go client.write()
  122. }

client.go

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. "github.com/gorilla/websocket"
  7. "github.com/satori/go.uuid"
  8. )
  9. type ClientManager struct {
  10. clients map[*Client]bool
  11. broadcast chan []byte
  12. register chan *Client
  13. unRegister chan *Client
  14. }
  15. type Client struct {
  16. id string
  17. socket *websocket.Conn
  18. send chan []byte
  19. }
  20. type Message struct {
  21. Sender string `json:"sender,omitempty"`
  22. Recipient string `json:"recipient,omitempty"`
  23. Content string `json:"content,omitempty"`
  24. }
  25. var manager = ClientManager{
  26. broadcast: make(chan []byte),
  27. register: make(chan *Client),
  28. unRegister: make(chan *Client),
  29. clients: make(map[*Client]bool),
  30. }
  31. func (manager *ClientManager) start() {
  32. for {
  33. select {
  34. case conn := <-manager.register:
  35. manager.clients[conn] = true
  36. jsonMessage, _ := json.Marshal(&Message{Content: conn.id + "/A new socket has connected."})
  37. manager.send(jsonMessage, conn)
  38. case conn := <-manager.unRegister:
  39. if _, ok := manager.clients[conn]; ok {
  40. close(conn.send)
  41. delete(manager.clients, conn)
  42. jsonMessage, _ := json.Marshal(&Message{Content: conn.id + "/A socket has disconnected."})
  43. manager.send(jsonMessage, conn)
  44. }
  45. case message := <-manager.broadcast:
  46. for conn := range manager.clients {
  47. select {
  48. case conn.send <- message:
  49. default:
  50. close(conn.send)
  51. delete(manager.clients, conn)
  52. }
  53. }
  54. }
  55. }
  56. }
  57. func (manager *ClientManager) send(message []byte, ignore *Client) {
  58. for conn := range manager.clients {
  59. if conn != ignore {
  60. conn.send <- message
  61. }
  62. }
  63. }
  64. func (c *Client) read() {
  65. defer func() {
  66. manager.unRegister <- c
  67. c.socket.Close()
  68. }()
  69. for {
  70. _, message, err := c.socket.ReadMessage()
  71. if err != nil {
  72. manager.unRegister <- c
  73. c.socket.Close()
  74. break
  75. }
  76. var content map[string]string
  77. json.Unmarshal(message, &content)
  78. if user, ok := content["user"]; ok {
  79. fmt.Print(user)
  80. }
  81. jsonMessage, _ := json.Marshal(&Message{Sender: c.id, Content: string(message)})
  82. manager.broadcast <- jsonMessage
  83. }
  84. }
  85. func (c *Client) write() {
  86. defer func() {
  87. c.socket.Close()
  88. }()
  89. for {
  90. select {
  91. case message, ok := <-c.send:
  92. if !ok {
  93. c.socket.WriteMessage(websocket.CloseMessage, []byte{})
  94. return
  95. }
  96. c.socket.WriteMessage(websocket.TextMessage, message)
  97. }
  98. }
  99. }
  100. func main() {
  101. fmt.Println("Starting application...")
  102. go manager.start()
  103. http.HandleFunc("/ws", wsPage)
  104. http.ListenAndServe(":8081", nil)
  105. }
  106. func wsPage(res http.ResponseWriter, req *http.Request) {
  107. u := &websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}
  108. conn, err := u.Upgrade(res, req, nil)
  109. if err != nil {
  110. http.NotFound(res, req)
  111. return
  112. }
  113. newUUID, err := uuid.NewV4()
  114. if err != nil {
  115. http.Error(res, "generate uuid error, please try again!", 900)
  116. return
  117. }
  118. client := &Client{id: newUUID.String(), socket: conn, send: make(chan []byte)}
  119. manager.register <- client
  120. go client.read()
  121. go client.write()
  122. }

index.html

  1. <html>
  2. <head>
  3. <title>Golang Chat</title>
  4. <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
  5. <script type="text/javascript">
  6. $(function() {
  7. var conn;
  8. var msg = $("#msg");
  9. var log = $("#log");
  10. function appendLog(msg) {
  11. var d = log[0]
  12. var doScroll = d.scrollTop == d.scrollHeight - d.clientHeight;
  13. msg.appendTo(log)
  14. if (doScroll) {
  15. d.scrollTop = d.scrollHeight - d.clientHeight;
  16. }
  17. }
  18. function strMapToObj(strMap) {
  19. let obj= Object.create(null);
  20. for (let[k,v] of strMap) {
  21. obj[k] = v;
  22. }
  23. return obj;
  24. }
  25. $("#form").submit(function() {
  26. if (!conn) {
  27. return false;
  28. }
  29. if (!msg.val()) {
  30. return false;
  31. }
  32. var Student = function () {
  33. this.msg = msg.val();
  34. this.user = '121212-454564';
  35. };
  36. conn.send(JSON.stringify(new Student));
  37. msg.val("");
  38. return false
  39. });
  40. if (window["WebSocket"]) {
  41. conn = new WebSocket("ws://localhost:8081/ws");
  42. conn.onerror = function (ev) {
  43. console.log(ev)
  44. }
  45. conn.onclose = function(evt) {
  46. console.log(evt)
  47. appendLog($("<div><b>Connection Closed.</b></div>"))
  48. }
  49. conn.onmessage = function(evt) {
  50. console.log(evt)
  51. appendLog($("<div/>").text(evt.data))
  52. }
  53. } else {
  54. appendLog($("<div><b>WebSockets Not Support.</b></div>"))
  55. }
  56. });
  57. </script>
  58. <style type="text/css">
  59. html {
  60. overflow: hidden;
  61. }
  62. body {
  63. overflow: hidden;
  64. padding: 0;
  65. margin: 0;
  66. width: 100%;
  67. height: 100%;
  68. background: gray;
  69. }
  70. #log {
  71. background: white;
  72. margin: 0;
  73. padding: 0.5em 0.5em 0.5em 0.5em;
  74. position: absolute;
  75. top: 0.5em;
  76. left: 0.5em;
  77. right: 0.5em;
  78. bottom: 3em;
  79. overflow: auto;
  80. }
  81. #form {
  82. padding: 0 0.5em 0 0.5em;
  83. margin: 0;
  84. position: absolute;
  85. bottom: 1em;
  86. left: 0px;
  87. width: 100%;
  88. overflow: hidden;
  89. }
  90. </style>
  91. </head>
  92. <body>
  93. <div id="log"></div>
  94. <form id="form">
  95. <input type="submit" value="发送" />
  96. <input type="text" id="msg" size="64"/>
  97. </form>
  98. </body>
  99. </html>

来源:
https://blog.csdn.net/wangshubo1989/article/details/78250790