/
server.go
116 lines (105 loc) · 2.48 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
package main
import (
"bufio"
"bytes"
"fmt"
"github.com/willf/bloom"
"net"
"strconv"
)
const (
CONN_HOST = "localhost"
CONN_PORT = 3333
SIZE = 1000000 // Size of the Bloom filter
HASH = 5 // Number of Hash functions
)
type (
ClientConn struct {
conn net.Conn
f *bloom.BloomFilter
}
Server struct {
listener net.Listener
f *bloom.BloomFilter
}
)
func main() {
server, err := NewServer(CONN_HOST+":"+strconv.Itoa(CONN_PORT), SIZE, HASH)
if server == nil {
panic("couldn't start listening: " + err.Error())
}
conns := clientConns(server.listener)
for {
go handleConn(&ClientConn{conn: <-conns, f: server.f})
}
}
// Creates a new TCP Server with a bloom filter (m, k)
func NewServer(dsn string, m uint, k uint) (*Server, error) {
listener, err := net.Listen("tcp", dsn)
if listener == nil {
return nil, err
}
f := bloom.New(m, k)
return &Server{listener: listener, f: f}, nil
}
// Accepts connections
func clientConns(listener net.Listener) chan net.Conn {
ch := make(chan net.Conn)
i := 0
go func() {
for {
client, err := listener.Accept()
if client == nil {
fmt.Printf("couldn't accept: " + err.Error())
continue
}
i++
fmt.Printf("%d: %v <-> %v\n", i, client.LocalAddr(),
client.RemoteAddr())
ch <- client
}
}()
return ch
}
// Handles connections: from a request, send a response
func handleConn(c *ClientConn) {
reader := bufio.NewReader(c.conn)
for {
request, err := reader.ReadBytes('\n')
if err != nil { // EOF, or worse
break
}
c.writeResponse(request)
}
c.conn.Close()
}
// The request should be of format
// ADD|ElementToAdd\n
// TEST|AmIHere
// writes back 200|true if the element is probably in the bloom filter
// writes back 200|false is the element is definitely not in the bloom filter
func (c *ClientConn) writeResponse(request []byte) {
message := bytes.Split(request, []byte{'|'})
var response []byte
if len(message) != 2 {
response = []byte("400|Malformed request\n Usage: ADD|ElementToAdd or TEST|ElementToTest\n")
c.conn.Write(response)
return
}
verb := string(message[0])
item := bytes.TrimSuffix(message[1], []byte("\n"))
if verb == "TEST" {
if c.f.Test(item) {
response = []byte("200|true\n")
} else {
response = []byte("200|false\n")
}
} else if verb == "ADD" {
c.f.Add(item)
response = []byte("201\n")
} else {
response = []byte("400|Unknown Verb\n")
}
c.conn.Write(response)
fmt.Println("Request:", string(request), "Response: ", string(response))
}