Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TCP server example #478

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions docs/examples/tcpserver.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
## Simple TCP/IP server that accepts both IPv4 and IPv6 connections
import chronos

# Because handleConn runs as an indepented task via `asyncSpawn`, it must
# handle all errors on its own (or the application will crash)
proc handleConn(transport: StreamTransport, done: Future[void]) {.
async: (raises: []).} =
# Handle a single remote connection
try:
echo "Incoming connection from ", transport.remoteAddress()

while true:
# Read and echo back lines until `q` or `0` is entered
let data = await transport.readLine(sep="\n")
if data.len > 0:
if data[0] == 'q':
if not done.finished():
# Notify server that it's time to stop - some other client could
# have done this already, so we check with `finished` first
done.complete()
break
elif data[0] == '0':
break # Stop reading and close the connection

echo "Echoed ", await transport.write(data & "\n"), " bytes"
except CancelledError:
raiseAssert "No cancellations in this example"
except TransportError as exc:
echo "Connection problem! ", exc.msg
finally:
# Connections must always be closed to avoid resource leaks
await transport.closeWait()

proc myApp(server: StreamServer) {.async.} =
echo "Accepting connections on ", server.local
let done = Future[void].init()
try:
while true:
let
accept = server.accept()

# Wait either for a new connection or that an existing connection signals
# that it's time to stop
discard await race(accept, done)
if done.finished(): break

# asyncSpawn is used to spawn an independent async task that runs until
# it's finished without blocking the current async function - the OS will
# clean up these tasks on shutdown but a long-running server will want to
# collect them and make sure their associated sockets are closed properly
asyncSpawn handleConn(accept.read(), done)
finally:
await server.closeWait()

let
# This server listens on both IPv4 and IPv6 and will pick a port number by
# itself
server = createStreamServer(AnyAddress6)

waitFor myApp(server)