Skip to content

Commit aa7bd47

Browse files
scottfeldmandeadprogram
authored andcommitted
examples: add classic network snake test example
Adding this example to test multiple concurrent socket connections.
1 parent e7931c6 commit aa7bd47

File tree

3 files changed

+184
-0
lines changed

3 files changed

+184
-0
lines changed

examples/net/snake/init.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//go:build ninafw || wioterminal
2+
3+
package main
4+
5+
import (
6+
"log"
7+
"time"
8+
9+
"tinygo.org/x/drivers/netlink"
10+
"tinygo.org/x/drivers/netlink/probe"
11+
)
12+
13+
var (
14+
ssid string
15+
pass string
16+
)
17+
18+
func init() {
19+
time.Sleep(2 * time.Second)
20+
21+
link, _ := probe.Probe()
22+
23+
err := link.NetConnect(&netlink.ConnectParams{
24+
Ssid: ssid,
25+
Passphrase: pass,
26+
})
27+
if err != nil {
28+
log.Fatal(err)
29+
}
30+
}

examples/net/snake/main.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// This example is the classic snake network test. The snake is feed a steady
2+
// diet of pkts and the pkts work themselves thru the snake segments and exit
3+
// the tail. Each snake segment is a TCP socket connection to a server. The
4+
// server echos pkts received back to the snake, and serves each segment on a
5+
// different port. (See server/main.go for server).
6+
//
7+
// snake | server
8+
// |
9+
// head ----->---|-->--+
10+
// seg a | |
11+
// +---<-|--<--+
12+
// | |
13+
// +-->--|-->--+
14+
// seg b | |
15+
// +---<-|--<--+
16+
// | |
17+
// +-->--|-->--+
18+
// seg c | |
19+
// +---<-|--<--+
20+
// | |
21+
// +-->--|-->--+
22+
// ... | |
23+
// +---<-|--<--+
24+
// | |
25+
// +-->--|-->--+
26+
// seg n | |
27+
// tail -------<-|--<--+
28+
// |
29+
30+
// The snake segments are linked by channels and each segment is run as a go
31+
// func. This forces segments to connect and run concurrently, which is a good
32+
// test of the underlying driver's ability to handle concurrent connections.
33+
34+
//go:build ninafw || wioterminal
35+
36+
package main
37+
38+
import (
39+
_ "embed"
40+
"fmt"
41+
"log"
42+
"net"
43+
"strings"
44+
"time"
45+
)
46+
47+
//go:embed main.go
48+
var code string
49+
50+
var (
51+
server string = "10.0.0.100:8080"
52+
)
53+
54+
func segment(in chan []byte, out chan []byte) {
55+
var buf [512]byte
56+
for {
57+
c, err := net.Dial("tcp", server)
58+
for ; err != nil; c, err = net.Dial("tcp", server) {
59+
println(err.Error())
60+
time.Sleep(5 * time.Second)
61+
}
62+
for {
63+
select {
64+
case msg := <-in:
65+
_, err := c.Write(msg)
66+
if err != nil {
67+
log.Fatal(err.Error())
68+
}
69+
time.Sleep(100 * time.Millisecond)
70+
n, err := c.Read(buf[:])
71+
if err != nil {
72+
log.Fatal(err.Error())
73+
}
74+
out <- buf[:n]
75+
}
76+
}
77+
}
78+
}
79+
80+
func feedit(head chan []byte) {
81+
for i := 0; i < 100; i++ {
82+
head <- []byte(fmt.Sprintf("\n---%d---\n", i))
83+
for _, line := range strings.Split(code, "\n") {
84+
if len(line) == 0 {
85+
line = " "
86+
}
87+
head <- []byte(line)
88+
}
89+
}
90+
}
91+
92+
var head = make(chan []byte)
93+
var a = make(chan []byte)
94+
var b = make(chan []byte)
95+
var c = make(chan []byte)
96+
var d = make(chan []byte)
97+
var e = make(chan []byte)
98+
var f = make(chan []byte)
99+
var tail = make(chan []byte)
100+
101+
func main() {
102+
103+
// The snake
104+
go segment(head, a)
105+
go segment(a, b)
106+
go segment(b, c)
107+
go segment(c, d)
108+
go segment(d, e)
109+
go segment(e, f)
110+
go segment(f, tail)
111+
112+
go feedit(head)
113+
114+
for {
115+
select {
116+
case msg := <-tail:
117+
println(string(msg))
118+
}
119+
}
120+
}

examples/net/snake/server/main.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package main
2+
3+
import (
4+
"io"
5+
"log"
6+
"net"
7+
)
8+
9+
func main() {
10+
// Listen for connections
11+
l, err := net.Listen("tcp", ":8080")
12+
if err != nil {
13+
log.Fatal(err.Error())
14+
}
15+
defer l.Close()
16+
println("Listening on port", ":8080")
17+
for {
18+
// Wait for a connection
19+
conn, err := l.Accept()
20+
if err != nil {
21+
log.Fatal(err)
22+
}
23+
println("Accepted connection from", conn.RemoteAddr().String())
24+
// Service the new connection in a goroutine.
25+
// The loop then returns to accepting, so that
26+
// multiple connections may be served concurrently
27+
go func(c net.Conn) {
28+
// Echo all incoming data
29+
io.Copy(c, c)
30+
// Shut down the connection
31+
c.Close()
32+
}(conn)
33+
}
34+
}

0 commit comments

Comments
 (0)