-
Notifications
You must be signed in to change notification settings - Fork 3
/
conn.go
160 lines (145 loc) · 3.45 KB
/
conn.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Copyright (c) 2020 Meng Huang ([email protected])
// This package is licensed under a MIT license that can be found in the LICENSE file.
package websocket
import (
"github.com/hslam/buffer"
"github.com/hslam/writer"
"io"
"math/rand"
"net"
"runtime"
"sync"
"sync/atomic"
"time"
)
var gcing int32
func gc() {
if atomic.CompareAndSwapInt32(&gcing, 0, 1) {
defer atomic.StoreInt32(&gcing, 1)
for i := 0; i < 24; i++ {
time.Sleep(time.Millisecond * 125)
runtime.GC()
}
}
}
// Conn represents a WebSocket connection.
type Conn struct {
reading sync.Mutex
writing sync.Mutex
isClient bool
random *rand.Rand
conn net.Conn
writer io.Writer
key string
accept string
path string
address string
shared bool
scheduling bool
readBufferSize int
readBuffer []byte
writeBufferSize int
writeBuffer []byte
buffer []byte
connBuffer []byte
readPool *buffer.Pool
writePool *buffer.Pool
closed int32
}
// Read implements the net.Conn Read method.
func (c *Conn) Read(b []byte) (n int, err error) {
if len(b) == 0 {
return 0, nil
}
c.reading.Lock()
if len(c.connBuffer) > 0 {
if len(b) >= len(c.connBuffer) {
n = copy(b, c.connBuffer)
c.connBuffer = c.connBuffer[:0]
c.reading.Unlock()
return
}
n = copy(b, c.connBuffer[:len(b)])
num := copy(c.connBuffer, c.connBuffer[len(b):])
c.connBuffer = c.connBuffer[:num]
c.reading.Unlock()
return
}
f, err := c.readFrame(nil)
if err == nil {
length := len(f.PayloadData)
if len(b) >= length {
copy(b, f.PayloadData)
c.putFrame(f)
c.reading.Unlock()
return length, nil
}
n = copy(b, f.PayloadData[:len(b)])
c.connBuffer = append(c.connBuffer, f.PayloadData[len(b):]...)
c.putFrame(f)
}
c.reading.Unlock()
return
}
func (c *Conn) read(b []byte) (n int, err error) {
return c.conn.Read(b)
}
// Write implements the net.Conn Write method.
func (c *Conn) Write(b []byte) (n int, err error) {
if len(b) == 0 {
return 0, nil
}
c.writing.Lock()
f := c.getFrame()
f.FIN = 1
f.Opcode = BinaryFrame
f.PayloadData = b
err = c.writeFrame(f)
if err == nil {
n = len(b)
}
c.writing.Unlock()
return
}
func (c *Conn) write(b []byte) (n int, err error) {
return c.writer.Write(b)
}
// Close closes the connection.
func (c *Conn) Close() error {
if !atomic.CompareAndSwapInt32(&c.closed, 0, 1) {
return nil
}
if w, ok := c.writer.(*writer.Writer); ok {
w.Close()
}
c.readBuffer = nil
c.writeBuffer = nil
c.buffer = nil
c.connBuffer = nil
go gc()
return c.conn.Close()
}
// LocalAddr returns the local network address.
// The Addr returned is shared by all invocations of LocalAddr, so
// do not modify it.
func (c *Conn) LocalAddr() net.Addr {
return c.conn.LocalAddr()
}
// RemoteAddr returns the remote network address.
// The Addr returned is shared by all invocations of RemoteAddr, so
// do not modify it.
func (c *Conn) RemoteAddr() net.Addr {
return c.conn.RemoteAddr()
}
// SetDeadline implements the Conn SetDeadline method.
func (c *Conn) SetDeadline(t time.Time) error {
return c.conn.SetDeadline(t)
}
// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *Conn) SetReadDeadline(t time.Time) error {
return c.conn.SetReadDeadline(t)
}
// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *Conn) SetWriteDeadline(t time.Time) error {
return c.conn.SetWriteDeadline(t)
}