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.