先安装依赖包:
go get github.com/gorilla/websocket
server.go
package main
import (
"encoding/json"
"fmt"
"net/http"
"github.com/gorilla/websocket"
"github.com/satori/go.uuid"
)
type ClientManager struct {
clients map[*Client]bool
broadcast chan []byte
register chan *Client
unRegister chan *Client
}
type Client struct {
id string
socket *websocket.Conn
send chan []byte
}
type Message struct {
Sender string `json:"sender,omitempty"`
Recipient string `json:"recipient,omitempty"`
Content string `json:"content,omitempty"`
}
var manager = ClientManager{
broadcast: make(chan []byte),
register: make(chan *Client),
unRegister: make(chan *Client),
clients: make(map[*Client]bool),
}
func (manager *ClientManager) start() {
for {
select {
case conn := <-manager.register:
manager.clients[conn] = true
jsonMessage, _ := json.Marshal(&Message{Content: conn.id + "/A new socket has connected."})
manager.send(jsonMessage, conn)
case conn := <-manager.unRegister:
if _, ok := manager.clients[conn]; ok {
close(conn.send)
delete(manager.clients, conn)
jsonMessage, _ := json.Marshal(&Message{Content: conn.id + "/A socket has disconnected."})
manager.send(jsonMessage, conn)
}
case message := <-manager.broadcast:
for conn := range manager.clients {
select {
case conn.send <- message:
default:
close(conn.send)
delete(manager.clients, conn)
}
}
}
}
}
func (manager *ClientManager) send(message []byte, ignore *Client) {
for conn := range manager.clients {
if conn != ignore {
conn.send <- message
}
}
}
func (c *Client) read() {
defer func() {
manager.unRegister <- c
c.socket.Close()
}()
for {
_, message, err := c.socket.ReadMessage()
if err != nil {
manager.unRegister <- c
c.socket.Close()
break
}
var content map[string]string
json.Unmarshal(message, &content)
if user, ok := content["user"]; ok {
fmt.Print(user)
}
jsonMessage, _ := json.Marshal(&Message{Sender: c.id, Content: string(message)})
manager.broadcast <- jsonMessage
}
}
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
}
c.socket.WriteMessage(websocket.TextMessage, message)
}
}
}
func main() {
fmt.Println("Starting application...")
go manager.start()
http.HandleFunc("/ws", wsPage)
http.ListenAndServe(":8081", nil)
}
func wsPage(res http.ResponseWriter, req *http.Request) {
u := &websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}
conn, err := u.Upgrade(res, req, nil)
if err != nil {
http.NotFound(res, req)
return
}
newUUID, err := uuid.NewV4()
if err != nil {
http.Error(res, "generate uuid error, please try again!", 900)
return
}
client := &Client{id: newUUID.String(), socket: conn, send: make(chan []byte)}
manager.register <- client
go client.read()
go client.write()
}
client.go
package main
import (
"encoding/json"
"fmt"
"net/http"
"github.com/gorilla/websocket"
"github.com/satori/go.uuid"
)
type ClientManager struct {
clients map[*Client]bool
broadcast chan []byte
register chan *Client
unRegister chan *Client
}
type Client struct {
id string
socket *websocket.Conn
send chan []byte
}
type Message struct {
Sender string `json:"sender,omitempty"`
Recipient string `json:"recipient,omitempty"`
Content string `json:"content,omitempty"`
}
var manager = ClientManager{
broadcast: make(chan []byte),
register: make(chan *Client),
unRegister: make(chan *Client),
clients: make(map[*Client]bool),
}
func (manager *ClientManager) start() {
for {
select {
case conn := <-manager.register:
manager.clients[conn] = true
jsonMessage, _ := json.Marshal(&Message{Content: conn.id + "/A new socket has connected."})
manager.send(jsonMessage, conn)
case conn := <-manager.unRegister:
if _, ok := manager.clients[conn]; ok {
close(conn.send)
delete(manager.clients, conn)
jsonMessage, _ := json.Marshal(&Message{Content: conn.id + "/A socket has disconnected."})
manager.send(jsonMessage, conn)
}
case message := <-manager.broadcast:
for conn := range manager.clients {
select {
case conn.send <- message:
default:
close(conn.send)
delete(manager.clients, conn)
}
}
}
}
}
func (manager *ClientManager) send(message []byte, ignore *Client) {
for conn := range manager.clients {
if conn != ignore {
conn.send <- message
}
}
}
func (c *Client) read() {
defer func() {
manager.unRegister <- c
c.socket.Close()
}()
for {
_, message, err := c.socket.ReadMessage()
if err != nil {
manager.unRegister <- c
c.socket.Close()
break
}
var content map[string]string
json.Unmarshal(message, &content)
if user, ok := content["user"]; ok {
fmt.Print(user)
}
jsonMessage, _ := json.Marshal(&Message{Sender: c.id, Content: string(message)})
manager.broadcast <- jsonMessage
}
}
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
}
c.socket.WriteMessage(websocket.TextMessage, message)
}
}
}
func main() {
fmt.Println("Starting application...")
go manager.start()
http.HandleFunc("/ws", wsPage)
http.ListenAndServe(":8081", nil)
}
func wsPage(res http.ResponseWriter, req *http.Request) {
u := &websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}
conn, err := u.Upgrade(res, req, nil)
if err != nil {
http.NotFound(res, req)
return
}
newUUID, err := uuid.NewV4()
if err != nil {
http.Error(res, "generate uuid error, please try again!", 900)
return
}
client := &Client{id: newUUID.String(), socket: conn, send: make(chan []byte)}
manager.register <- client
go client.read()
go client.write()
}
index.html
<html>
<head>
<title>Golang Chat</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
var conn;
var msg = $("#msg");
var log = $("#log");
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;
}
}
function strMapToObj(strMap) {
let obj= Object.create(null);
for (let[k,v] of strMap) {
obj[k] = v;
}
return obj;
}
$("#form").submit(function() {
if (!conn) {
return false;
}
if (!msg.val()) {
return false;
}
var Student = function () {
this.msg = msg.val();
this.user = '121212-454564';
};
conn.send(JSON.stringify(new Student));
msg.val("");
return false
});
if (window["WebSocket"]) {
conn = new WebSocket("ws://localhost:8081/ws");
conn.onerror = function (ev) {
console.log(ev)
}
conn.onclose = function(evt) {
console.log(evt)
appendLog($("<div><b>Connection Closed.</b></div>"))
}
conn.onmessage = function(evt) {
console.log(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>
来源:
https://blog.csdn.net/wangshubo1989/article/details/78250790
搜索
标签
study
ab
amap
apache
apahe
awk
aws
bat
centos
CFS
chrome
cmd
cnpm
composer
consul
crontab
css
curl
cygwin
devops
di
docker
docker,docker-compose
ethereum
excel
fiddler
fluentd
framework
front-end
git
gitgui
github
glide
go
golang
gorm
grafana
gzip
ioc
item2
iterm2
javascript
jenkins
jsonp
kafka
laradock
laravel
larval
linux
liunux
log
mac
mac, wi-fi
macos
magento
mariaDB
minikube
mongoDB
msp
mysql
netbeans
nginx
nodejs
nohup
npm
nsq
oracle
php
php-fpm
php7
phpstorm
php扩展
Protobuf
python
redis
scp
server
shell
soap
socket
socket5
sql
sre
ssdb
ssh
ssl
study
sublime
swift
system
td-agent
uml
v2ray
vagrant
vagrnat
vim
vpn
vue
vue.js
webpack
webrtc
websocket
webtatic
windows
windows7
word
wps
xdebug
yarn
yii2
yum
zookeeper
世界国家
互联网
以太坊
分类
前端
小程序
打印机
排序算法
搞笑
权限
粤语
缓存
网络
虚拟机
视频
设计模式
项目管理
热门文章
友情链接