/
chat-server.go
178 lines (157 loc) · 4.87 KB
/
chat-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
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package main
import (
"bytes"
"container/list"
"flag"
"fmt"
"log"
"net"
"os"
"strings"
)
// flag for debuging info. or a simple log
var debug = flag.Bool("d", false, "set the debug modus( print informations )")
type ClientChat struct {
Name string // name of user
IN chan string // input channel for to send to user
OUT chan string // input channel from user to all
Con *net.Conn // connection of client
Quit chan bool // quit channel for all goroutines
ListChain *list.List // reference to list
}
// read from connection and return true if ok
func (c *ClientChat) Read(buf []byte) bool {
nr, err := c.Con.Read(buf)
if err != nil {
c.Close()
return false
}
Log("Read(): ", nr, " bytes")
return true
}
// close the connection and send quit to sender
func (c *ClientChat) Close() {
c.Quit <- true
c.Con.Close()
c.deleteFromList()
}
// compare two clients: name and network connection
func (c *ClientChat) Equal(cl *ClientChat) bool {
if bytes.Equal(strings.Bytes(c.Name), strings.Bytes(cl.Name)) {
if c.Con == cl.Con {
return true
}
}
return false
}
// delete the client from list
func (c *ClientChat) deleteFromList() {
for e := c.ListChain.Front(); e != nil; e = e.Next() {
client := e.Value.(ClientChat)
if c.Equal(&client) {
Log("deleteFromList(): ", c.Name)
c.ListChain.Remove(e)
}
}
}
// func Log(v ...): loging. give log information if debug is true
func Log(v ...interface{}) {
if *debug == true {
ret := fmt.Sprint(v)
log.Stdoutf("SERVER: %s", ret)
}
}
// func test(): testing for error
func test(err os.Error, mesg string) {
if err != nil {
log.Stderr("SERVER: ERROR: ", mesg)
os.Exit(-1)
} else {
Log("Ok: ", mesg)
}
}
// handlingINOUT(): handle inputs from client, and send it to all other client via channels.
func handlingINOUT(IN <-chan string, lst *list.List) {
for {
Log("handlingINOUT(): wait for input")
input := <-IN // input, get from client
// send to all client back
Log("handlingINOUT(): handling input: ", input)
for value := range lst.Iter() {
client := value.(ClientChat)
Log("handlingINOUT(): send to client: ", client.Name)
client.IN <- input
}
}
}
// clientreceiver wait for an input from network, after geting data it send to
// handlingINOUT via a channel.
func clientreceiver(client *ClientChat) {
buf := make([]byte, 2048)
Log("clientreceiver(): start for: ", client.Name)
for client.Read(buf) {
if bytes.Equal(buf, strings.Bytes("/quit")) {
client.Close()
break
}
Log("clientreceiver(): received from ", client.Name, " (", string(buf), ")")
send := client.Name + "> " + string(buf)
client.OUT <- send
for i := 0; i < 2048; i++ {
buf[i] = 0x00
}
}
client.OUT <- client.Name + " has left chat"
Log("clientreceiver(): stop for: ", client.Name)
}
// clientsender(): get the data from handlingINOUT via channel (or quit signal from
// clientreceiver) and send it via network
func clientsender(client *ClientChat) {
Log("clientsender(): start for: ", client.Name)
for {
Log("clientsender(): wait for input to send")
select {
case buf := <-client.IN:
Log("clientsender(): send to \"", client.Name, "\": ", string(buf))
client.Con.Write(strings.Bytes(buf))
case <-client.Quit:
Log("clientsender(): client want to quit")
client.Con.Close()
break
}
}
Log("clientsender(): stop for: ", client.Name)
}
// clientHandling(): get the username and create the clientsturct
// start the clientsender/receiver, add client to list.
func clientHandling(con *net.Conn, ch chan string, lst *list.List) {
buf := make([]byte, 1024)
con.Read(buf)
name := string(buf)
newclient := &ClientChat{name, make(chan string), ch, con, make(chan bool), lst}
Log("clientHandling(): for ", name)
go clientsender(newclient)
go clientreceiver(newclient)
lst.PushBack(*newclient)
ch <- name + " has joinet the chat"
}
func main() {
flag.Parse()
Log("main(): start")
// create the list of clients
clientlist := list.New()
in := make(chan string)
Log("main(): start handlingINOUT()")
go handlingINOUT(in, clientlist)
// create the connection
netlisten, err := net.Listen("tcp", "127.0.0.1:9988")
test(err, "main Listen")
defer netlisten.Close()
for {
// wait for clients
Log("main(): wait for client ...")
conn, err := netlisten.Accept()
test(err, "main: Accept for client")
go clientHandling(&conn, in, clientlist)
}
}