6. echo (serial, betterC)
import core.sys.linux.fcntl, core.sys.linux.errno, core.sys.linux.netinet.tcp,
core.sys.linux.netinet.in_, core.sys.posix.sys.socket, core.sys.posix.unistd,
core.sys.posix.netdb;
import core.stdc.stdio;
import core.stdc.string : strerror;
int server(ushort port) {
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(port);
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0)
return -1;
int flags = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, cast(void*)&flags, int.sizeof);
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, cast(void*)&flags, int.sizeof);
if (bind(fd, cast(sockaddr*)&addr, addr.sizeof) == -1) {
fd.close;
return -1;
}
if (listen(fd, 4) == -1) {
fd.close;
return -1;
}
return fd;
}
extern (C) int main() {
enum PORT = 4444;
int listener = server(PORT);
if (listener == -1) {
fprintf(stderr, "Failed to init server : %d : %s\n", errno, strerror(errno));
return 1;
}
printf("Listening on %d.\n", PORT);
sockaddr_storage addr;
socklen_t addrlen = addr.sizeof;
char[NI_MAXHOST] hoststr;
char[NI_MAXSERV] portstr;
ubyte[4096] buf;
while (true) {
int client = listener.accept(cast(sockaddr*)&addr, &addrlen);
if (client < 0) {
fprintf(stderr, "Failed to accept socket : %d : %s\n", errno, strerror(errno));
listener.close;
return 1;
}
getnameinfo(cast(sockaddr*)&addr, addrlen, hoststr.ptr, hoststr.sizeof, portstr.ptr, portstr.sizeof,
NI_NUMERICHOST | NI_NUMERICSERV);
printf("Received connection from %s:%s.\n", hoststr.ptr, portstr.ptr);
while (true) {
ptrdiff_t len = client.recv(cast(void*)&buf, buf.sizeof, 0);
if (len <= 0)
break;
if (client.send(cast(void*)&buf, len, 0) < 0)
break;
}
client.close;
printf("Lost connection from %s:%s.\n", hoststr.ptr, portstr.ptr);
}
}
This server is basically identical to echo serial, except that it only uses libc for networking, and it can be compiled with -betterC. Fun fact: this version compiles in 6%-10% of the time of the other version.