v / vlib / net
Raw file | 138 loc (129 sloc) | 3.09 KB | Latest commit hash 017ace6ea
1module main
2
3import net
4import time
5
6const xport = 15523
7
8struct Context {
9mut:
10 ok_client_dials int
11 fail_client_dials int
12 //
13 ok_client_close int
14 fail_client_close int
15 ////
16 ok_server_accepts int
17 fail_server_accepts int
18 //
19 ok_server_close int
20 fail_server_close int
21 //
22 received []int
23}
24
25fn elog(msg string) {
26 eprintln('${time.now().format_ss_micro()} | ${msg}')
27}
28
29fn receive_data(mut con net.TcpConn, shared ctx Context) {
30 mut buf := []u8{len: 5}
31 for {
32 bytes := con.read(mut buf) or { -1 }
33 if bytes < 0 {
34 break
35 }
36 if bytes > 0 {
37 lock ctx {
38 ctx.received << buf[0]
39 }
40 }
41 }
42 con.close() or {
43 lock ctx {
44 ctx.fail_server_close++
45 }
46 return
47 }
48 lock ctx {
49 ctx.ok_server_close++
50 }
51}
52
53fn start_server(schannel chan int, shared ctx Context) {
54 elog('server: start_server')
55 mut tcp_listener := net.listen_tcp(net.AddrFamily.ip, ':${xport}') or {
56 elog('server: start server error ${err}')
57 return
58 }
59 elog('server: server started listening at port :${xport}')
60 schannel <- 0
61
62 for {
63 mut tcp_con := tcp_listener.accept() or {
64 elog('server: accept error: ${err}')
65 lock ctx {
66 ctx.fail_server_accepts++
67 }
68 continue
69 }
70 spawn receive_data(mut tcp_con, shared ctx)
71 lock ctx {
72 ctx.ok_server_accepts++
73 }
74 elog('server: new tcp connection con.sock.handle: ${tcp_con.sock.handle}')
75 continue
76 }
77}
78
79fn start_client(i int, shared ctx Context) {
80 elog('client [${i}]: start')
81 mut tcp_con := net.dial_tcp('127.0.0.1:${xport}') or {
82 elog('client [${i}]: net.dial_tcp err ${err}')
83 lock ctx {
84 ctx.fail_client_dials++
85 }
86 return
87 }
88 lock ctx {
89 ctx.ok_client_dials++
90 }
91 elog('client [${i}]: conn is connected, con.sock.handle: ${tcp_con.sock.handle}')
92 tcp_con.write([u8(i)]) or { elog('client [${i}]: write failed, err: ${err}') }
93 time.sleep(1 * time.second)
94 elog('client [${i}]: closing connection...')
95 tcp_con.close() or {
96 elog('client [${i}]: close failed, err: ${err}')
97 lock ctx {
98 ctx.fail_client_close++
99 }
100 return
101 }
102 lock ctx {
103 ctx.ok_client_close++
104 }
105}
106
107fn test_tcp_self_dialing() {
108 elog('>>> start')
109 start_time := time.now()
110 shared ctx := &Context{}
111 mut server_channel := chan int{cap: 1}
112 spawn start_server(server_channel, shared ctx)
113 svalue := <-server_channel
114 elog('>>> server was started: ${svalue}. Starting clients:')
115 for i := int(0); i < 20; i++ {
116 spawn start_client(i, shared ctx)
117 elog('>>> started client ${i}')
118 // time.sleep(2 * time.millisecond)
119 }
120 max_dt := 5 * time.second
121 for {
122 t := time.now()
123 dt := t - start_time
124 if dt > max_dt {
125 elog('>>> exiting after ${dt.milliseconds()} ms ...')
126 lock ctx {
127 // TODO: fix `dump(ctx)`, when `shared ctx := Type{}`
128 final_value_for_ctx := ctx // make a value copy as a temporary workaround. TODO: remove when dump(ctx) works.
129 dump(final_value_for_ctx)
130 assert ctx.fail_client_dials < 2, 'allowed failed client dials, from ${ctx.ok_server_accepts} connections'
131 assert ctx.received.len > ctx.ok_server_accepts / 2, 'at least half the clients sent some data, that was later received by the server'
132 }
133 elog('>>> goodbye')
134 exit(0)
135 }
136 time.sleep(10 * time.millisecond)
137 }
138}