-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.go
133 lines (118 loc) · 2.87 KB
/
server.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
package module
import (
"fmt"
"io"
"net"
"strconv"
"sync"
"time"
)
var _ = strconv.ErrRange
type ServerObj struct {
Ip string
Port int
OnlineMap map[int]*User //在线用户mapping
mapLock sync.RWMutex //为在线用户映射加一个读写锁
Message chan string //总消息管道
}
//进行初始化
func NewServer(ip string, port int) *ServerObj {
server := &ServerObj{
Ip: ip,
Port: port,
OnlineMap: make(map[int]*User),
Message: make(chan string),
}
return server
}
//进行消息广播
func (this *ServerObj) BroadCast(user *User, msg string) {
uid := strconv.Itoa(user.Uid)
msg = "[" + uid + "]" + user.Name + " " + msg + "\n"
//用strings.Builder 方式是 稳定性和效率最高的,就是写起来比较麻烦
// var builder strings.Builder
// builder.Grow(50)
// builder.WriteString("[")
// builder.WriteRune(rune(user.Uid))
// builder.WriteString("]" + user.Name + " " + msg + "\n")
// msg = builder.String()
this.Message <- msg
}
//监听server消息管道,放到全部用户管道中
func (this *ServerObj) ListenMessager() {
for {
msg := <-this.Message
//别忘记加锁
this.mapLock.Lock()
for _, user := range this.OnlineMap {
user.C <- msg
}
this.mapLock.Unlock()
}
}
//启动服务
func (this *ServerObj) Start() {
listener, err := net.Listen("tcp4", fmt.Sprintf("%s:%d", this.Ip, this.Port))
if err != nil {
fmt.Println("net.Listen err :", err)
return
}
fmt.Println("listening ip:", this.Ip, " and port:", this.Port)
//关闭连接
defer listener.Close()
//监听广播消息
go this.ListenMessager()
//处理连接
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("listener.Accept err", err)
continue
}
//要并行处理链接
go this.Handler(conn)
}
}
//处理新用户链接
//user指针写入mapping中
//新加入用户消息金星广播
func (this *ServerObj) Handler(conn net.Conn) {
user := NewUser(conn, this)
//用户上线
user.Online()
isLive := make(chan bool) //用户是否活跃管道
//接受客户端消息进行广播(群聊)
go func() {
for{
buf := make([]byte, 4096)
n, err := conn.Read(buf)
//用户下线
if n == 0 {
user.Offline()
return
}
if err != nil && err != io.EOF {
fmt.Println("conn read err:", err)
return
}
//获取用户消息去除结尾\n
msg := string(buf[:n-1])
user.ExecMessage(msg)
isLive <- true
}
}()
//阻塞当前handler,注意一定要有真实的goroutine在跑,否则select{}会报panic
for{
select {
case <-isLive:
//什么都不用做,为了激活select,等待time.after到期后的逻辑执行
case <-time.After(1000 * time.Second):
//超时踢出用户
user.SendMessage("您已超时,被踢出...\n")
//销毁资源和关闭链接
close(user.C)
conn.Close()
return //或是 runtime.Goexit退出
}
}
}