2. echo (serial)
import std.socket : InternetAddress, Socket, TcpSocket, SocketOptionLevel, SocketOption, Address; import std.stdio : writefln; import std.typecons : Unique; enum port = 4444; void main() { Unique!TcpSocket listener = new TcpSocket; listener.blocking = true; listener.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, 1); listener.bind(new InternetAddress(port)); listener.listen(10); writefln!"Listening on %d."(port); ubyte[4096] buf; ptrdiff_t len; while (true) { Unique!Socket client = listener.accept; Unique!Address remote = client.remoteAddress; writefln!"Received connection from %s."(remote.toString); while (0 < (len = client.receive(buf[]))) { client.send(buf[0 .. len]); } writefln!"Lost connection from %s."(remote.toString); } }
This server accepts one connection at a time, receives up to 4k bytes from it and then echoes them back immediately, reusing the buffer. The buffer uses a static array, a value type, and slices it twice: first, so that receive
can pass the slice ptr and length to the underlying syscall, and second, so that send
can do the same with the exact length of bytes received. When a receive returns 0 (on connection close) or a negative number (on error), the inner loop ends and client
is destructed with the end of the outer loop, closing it.
Client interaction
$ ncat localhost 4444 this is a line of input ... followed by this is a line of input ... followed by ^^ an echo from the server ^^ an echo from the server
$ ncat localhost 4444 < echo > echo.out $ diff -s echo echo.out Files echo and echo.out are identical
what's with setting listener.blocking
?
Blocking is the default for a TcpSocket, so this is a no-op.
why is the address saved in a local variable?
It's an error to ask for a closed socket'sremoteAddress
what's with these Unique
types?
In all cases in this code, scope
would work just as well. These will show up in a few more servers but at most force Socket destructors to run at the end of a scope.
is this server fit for purpose?
This one's a lot less defensible than the previous server which just responded to connections with a packet and closed them immediately. This server is unavailable for use while a single connection has it open, and a denial-of-service attack is as simple asncat server 4444 </dev/zero
. An echo server really needs to handle concurrent connections.