GO提供原生的websocket API,使用时go get然后引用即可golang.org/x/net/websocket
使用起来也很方便,直接上代码吧。
一个echo server的代码
package main
import(
"golang.org/x/net/websocket"
"fmt"
"net/http"
"flag"
)
type WSServer struct {
ListenAddr string
}
func (this *WSServer)handler(conn *websocket.Conn){
fmt.Printf("a new ws conn: %s->%s\n", conn.RemoteAddr().String(), conn.LocalAddr().String())
var err error
for {
var reply string
err = websocket.Message.Receive(conn, &reply)
if err != nil {
fmt.Println("receive err:",err.Error())
break
}
fmt.Println("Received from client: " + reply)
if err = websocket.Message.Send(conn, reply); err != nil {
fmt.Println("send err:", err.Error())
break
}
}
}
func (this *WSServer)start()(error){
http.Handle("/ws", websocket.Handler(this.handler))
fmt.Println("begin to listen")
err := http.ListenAndServe(this.ListenAddr, nil)
if err != nil {
fmt.Println("ListenAndServe:", err)
return err
}
fmt.Println("start end")
return nil
}
func main(){
addr := flag.String("a", "127.0.1.1:12345", "websocket server listen address")
flag.Parse()
wsServer := &WSServer{
ListenAddr : *addr,
}
wsServer.start()
fmt.Println("------end-------")
}
上述代码中,每来一个新的websocket client,server会起一个goroutine执行WSSever的handler函数。
websocket client代码实例
package main
import (
"flag"
"fmt"
"time"
"golang.org/x/net/websocket"
)
var addr = flag.String("addr", "127.0.0.1:12345", "http service address")
func main() {
flag.Parse()
url := "ws://"+ *addr + "/ws"
origin := "test://1111111/"
ws, err := websocket.Dial(url, "", origin)
if err != nil {
fmt.Println(err)
}
go timeWriter(ws)
for {
var msg [512]byte
_, err := ws.Read(msg[:])//此处阻塞,等待有数据可读
if err != nil {
fmt.Println("read:", err)
return
}
fmt.Printf("received: %s\n", msg)
}
}
func timeWriter(conn *websocket.Conn) {
for {
time.Sleep(time.Second * 2)
websocket.Message.Send(conn, "hello world")
}
}
client的代码,每隔2秒钟发送hello world到server,然后阻塞在Read函数。需要注意的是origin必须以“http://1111111/” 这种标准的URI格式,否则报错“invalid URI for request”。
关闭进程、网络断线等异常情况
关闭进程
无论server还是client,关闭进程,对端Read都会立刻收到EOF,对EOF做处理即可。
网络断线
- 测试
client和server部署在不同机器上,client每隔2秒中向server发送数据,server收到后回吐给客户端。这个过程中,拔掉client的网线。 - 测试结果
- 断网后,client一定时间内写都能成功返回,但是因为断网实际没有发送出去,数据写到了底层tcp的缓冲区。
- 过一段时间后,1分钟左右,client Read返回错误“read: operation timed out”。Write会返回“write: broken pipe”。这个可能是Go中websocket实现时加了超时机制,也有可能是设置了底层TCP SO_KEEPALIVE,检测到了网络不可用。
- 在Read/Write返回错误之前,重新连上网络,可以继续发送和接受数据。这个可以从TCP的实现上解释。TCP连接并不是物理连接,本质上就是连接两端各自系统内核维护的一个四元组。客户端断线,在一定时间内并不会导致四元组的释放。所以当连上网线后此TCP连接可以自动恢复,继续进行正常的网络操作。
- 断线重连到其他网络,相当于断网。这个很好解释,连上其他网络,IP地址都改变了,之前的四元组不可用。
--------------------- 本文来自 阿冬哥 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/c359719435/article/details/78845719?utm_source=copy