Phil Eaton made a repository of Barebones UNIX socket servers with this description:
I find myself writing this server in some language every few months. Each time I have to scour the web for a good reference. Use this as a reference to write your own bare server in C or other languages with a UNIX API (Python, OCaml, etc).
Many developers learning network programming will encounter Beej's Guide to Network Programming which uses the sockets API, has been ported to many platforms, and explains the intricacies of making computers talk to each other in this manner.
C
We can take a look at his C implementation of a server that listens on port 15000, accepts client connections, reads up to 1024 bytes which are printed to the screen, then writes hello world
back to the client and disconnects them:
#include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <unistd.h> int main() { int server, client; socklen_t addrlen; int bufsize = 1024; char *buffer = malloc(bufsize); struct sockaddr_in address; server = socket(AF_INET, SOCK_STREAM, 0); address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(15000); bind(server, (struct sockaddr *) &address, sizeof(address)); while (1) { listen(server, 10); client = accept(server, (struct sockaddr *) &address, &addrlen); recv(client, buffer, bufsize, 0); printf("%s\n", buffer); write(client, "hello world\n", 12); close(client); } close(server); return 0; }
Factor
A direct Factor translation — without any error checking, like in the original example — using the C library interface might look something like this:
USING: accessors alien.c-types alien.data byte-arrays classes.struct io io.encodings.string io.encodings.utf8 kernel sequences unix.ffi unix.types ; :: reference-server ( -- ) 1024 <byte-array> :> buffer AF_INET SOCK_STREAM 0 socket :> server sockaddr-in malloc-struct AF_INET >>family 0 >>addr 15000 htons >>port :> address server address sockaddr-in heap-size bind drop [ server 10 listen drop server address 0 socklen_t <ref> accept :> client client buffer 1024 0 recv buffer swap head-slice utf8 decode print flush client $[ "hello world\n" >byte-array ] dup length unix.ffi:write drop client close drop t ] loop server close drop ;
I noticed that some of his examples are more idiomatic to the language, so we could rewrite this using threaded servers — gaining the benefit of working on Windows as well as error handling and logging — using a handler quotation to implement the read/print/write/disconnect logic.
USING: accessors io io.encodings.binary io.encodings.string io.encodings.utf8 io.servers kernel namespaces ; : reference-server ( -- ) binary <threaded-server> 15000 >>insecure [ 1024 read-partial [ [ utf8 decode print flush ] with-global $[ "hello world\n" >byte-array ] io:write flush ] when* ] >>handler start-server wait-for-server ;
This is available on my GitHub.