2022-08-07 10:40:05 +03:00
|
|
|
module main
|
|
|
|
|
|
|
|
import net
|
|
|
|
import time
|
|
|
|
|
|
|
|
const xport = 15523
|
|
|
|
|
|
|
|
struct Context {
|
|
|
|
mut:
|
|
|
|
ok_client_dials int
|
|
|
|
fail_client_dials int
|
|
|
|
//
|
|
|
|
ok_client_close int
|
|
|
|
fail_client_close int
|
|
|
|
////
|
|
|
|
ok_server_accepts int
|
|
|
|
fail_server_accepts int
|
|
|
|
//
|
|
|
|
ok_server_close int
|
|
|
|
fail_server_close int
|
|
|
|
//
|
|
|
|
received []int
|
|
|
|
}
|
|
|
|
|
|
|
|
fn elog(msg string) {
|
|
|
|
eprintln('$time.now().format_ss_micro() | $msg')
|
|
|
|
}
|
|
|
|
|
2022-08-20 13:32:53 +03:00
|
|
|
fn receive_data(mut con net.TcpConn, shared ctx Context) {
|
2022-08-07 10:40:05 +03:00
|
|
|
mut buf := []u8{len: 5}
|
|
|
|
for {
|
|
|
|
bytes := con.read(mut buf) or { -1 }
|
|
|
|
if bytes < 0 {
|
|
|
|
break
|
|
|
|
}
|
2022-08-20 13:32:53 +03:00
|
|
|
if bytes > 0 {
|
|
|
|
lock ctx {
|
|
|
|
ctx.received << buf[0]
|
|
|
|
}
|
|
|
|
}
|
2022-08-07 10:40:05 +03:00
|
|
|
}
|
|
|
|
con.close() or {
|
2022-08-20 13:32:53 +03:00
|
|
|
lock ctx {
|
|
|
|
ctx.fail_server_close++
|
|
|
|
}
|
2022-08-07 10:40:05 +03:00
|
|
|
return
|
|
|
|
}
|
2022-08-20 13:32:53 +03:00
|
|
|
lock ctx {
|
|
|
|
ctx.ok_server_close++
|
|
|
|
}
|
2022-08-07 10:40:05 +03:00
|
|
|
}
|
|
|
|
|
2022-08-20 13:32:53 +03:00
|
|
|
fn start_server(schannel chan int, shared ctx Context) {
|
2022-08-07 10:40:05 +03:00
|
|
|
elog('server: start_server')
|
|
|
|
mut tcp_listener := net.listen_tcp(net.AddrFamily.ip, ':$xport') or {
|
|
|
|
elog('server: start server error $err')
|
|
|
|
return
|
|
|
|
}
|
|
|
|
elog('server: server started listening at port :$xport')
|
|
|
|
schannel <- 0
|
|
|
|
|
|
|
|
for {
|
|
|
|
mut tcp_con := tcp_listener.accept() or {
|
|
|
|
elog('server: accept error: $err')
|
2022-08-20 13:32:53 +03:00
|
|
|
lock ctx {
|
|
|
|
ctx.fail_server_accepts++
|
|
|
|
}
|
2022-08-07 10:40:05 +03:00
|
|
|
continue
|
|
|
|
}
|
2022-08-20 13:32:53 +03:00
|
|
|
go receive_data(mut tcp_con, shared ctx)
|
|
|
|
lock ctx {
|
|
|
|
ctx.ok_server_accepts++
|
|
|
|
}
|
2022-08-07 10:40:05 +03:00
|
|
|
elog('server: new tcp connection con.sock.handle: $tcp_con.sock.handle')
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-20 13:32:53 +03:00
|
|
|
fn start_client(i int, shared ctx Context) {
|
2022-08-07 10:40:05 +03:00
|
|
|
elog('client [$i]: start')
|
|
|
|
mut tcp_con := net.dial_tcp('127.0.0.1:$xport') or {
|
|
|
|
elog('client [$i]: net.dial_tcp err $err')
|
2022-08-20 13:32:53 +03:00
|
|
|
lock ctx {
|
|
|
|
ctx.fail_client_dials++
|
|
|
|
}
|
2022-08-07 10:40:05 +03:00
|
|
|
return
|
|
|
|
}
|
2022-08-20 13:32:53 +03:00
|
|
|
lock ctx {
|
|
|
|
ctx.ok_client_dials++
|
|
|
|
}
|
2022-08-07 10:40:05 +03:00
|
|
|
elog('client [$i]: conn is connected, con.sock.handle: $tcp_con.sock.handle')
|
|
|
|
tcp_con.write([u8(i)]) or { elog('client [$i]: write failed, err: $err') }
|
|
|
|
time.sleep(1 * time.second)
|
|
|
|
elog('client [$i]: closing connection...')
|
|
|
|
tcp_con.close() or {
|
|
|
|
elog('client [$i]: close failed, err: $err')
|
2022-08-20 13:32:53 +03:00
|
|
|
lock ctx {
|
|
|
|
ctx.fail_client_close++
|
|
|
|
}
|
2022-08-07 10:40:05 +03:00
|
|
|
return
|
|
|
|
}
|
2022-08-20 13:32:53 +03:00
|
|
|
lock ctx {
|
|
|
|
ctx.ok_client_close++
|
|
|
|
}
|
2022-08-07 10:40:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn test_tcp_self_dialing() {
|
|
|
|
elog('>>> start')
|
|
|
|
start_time := time.now()
|
2022-08-20 13:32:53 +03:00
|
|
|
shared ctx := &Context{}
|
2022-08-07 10:40:05 +03:00
|
|
|
mut server_channel := chan int{cap: 1}
|
2022-08-20 13:32:53 +03:00
|
|
|
go start_server(server_channel, shared ctx)
|
2022-08-07 10:40:05 +03:00
|
|
|
svalue := <-server_channel
|
|
|
|
elog('>>> server was started: ${svalue}. Starting clients:')
|
|
|
|
for i := int(0); i < 20; i++ {
|
2022-08-20 13:32:53 +03:00
|
|
|
go start_client(i, shared ctx)
|
2022-08-07 10:40:05 +03:00
|
|
|
elog('>>> started client $i')
|
|
|
|
// time.sleep(2 * time.millisecond)
|
|
|
|
}
|
|
|
|
max_dt := 5 * time.second
|
|
|
|
for {
|
|
|
|
t := time.now()
|
|
|
|
dt := t - start_time
|
|
|
|
if dt > max_dt {
|
|
|
|
elog('>>> exiting after $dt.milliseconds() ms ...')
|
2022-08-20 13:32:53 +03:00
|
|
|
lock ctx {
|
|
|
|
// TODO: fix `dump(ctx)`, when `shared ctx := Type{}`
|
|
|
|
final_value_for_ctx := ctx // make a value copy as a temporary workaround. TODO: remove when dump(ctx) works.
|
|
|
|
dump(final_value_for_ctx)
|
|
|
|
assert ctx.fail_client_dials < 2, 'allowed failed client dials, from $ctx.ok_server_accepts connections'
|
|
|
|
assert ctx.received.len > ctx.ok_server_accepts / 2, 'at least half the clients sent some data, that was later received by the server'
|
|
|
|
}
|
2022-08-07 10:40:05 +03:00
|
|
|
elog('>>> goodbye')
|
|
|
|
exit(0)
|
|
|
|
}
|
|
|
|
time.sleep(10 * time.millisecond)
|
|
|
|
}
|
|
|
|
}
|