_PROGRAMMER'S BOOKSHELF COLUMN_ by Andrew Schulman [FIGURE 1: (a) non-networking ``hello world'' (b) networking ``hello world''] (a) /* HELLO.C */ main() { puts("hello world"); } (b) typedef struct { int request; int len; char buf[MAX]; } REQUEST_PACKET; /* client requests to server */ typedef unsigned REPLY_PACKET; /* server replies to client */ /* H_CLIENT.C */ main() { REQUEST_PACKET requ; REPLY_PACKET reply; char *msg = "hello world"; conn = call(machine_running_H_SERVER); requ.request = DISPLAY; requ.len = strlen(msg); strcpy(requ.buf, msg); send(conn, &requ, sizeof(REQUEST_PACKET)); receive(conn, &reply, sizeof(REPLY_PACKET)); puts(reply == OK ? "ok" : "fail"); hangup(conn); } /* H_SERVER.C */ main() { REQUEST_PACKET requ; REPLY_PACKET ok = OK; for (;;) /* endless loop */ { conn = listen(anyone); receive(conn, &requ, sizeof(REQUEST_PACKET)); switch (requ.request) { case DISPLAY: printf("%*s\n", requ.len, requ.buf); send(conn, &ok, sizeof(REPLY_PACKET)); break; // handle other requests } hangup(conn); } } [FIGURE 2: No-wait networking ``hello'' server] /* H_SERVER.C */ hangup_handler() /* called when hangup completes */ { // free any buffers allocated in listen_handler, etc. } send_handler() /* called when send completes */ { // do nothing } receive_handler(requ) /* called when receive completes */ { REPLY_PACKET ok = OK; switch (requ.request) { case DISPLAY: printf("%*s\n", requ.len, requ.buf); send_nowait(conn, &ok, sizeof(REPLY_PACKET), send_handler); break; // handle other requests } hangup_nowait(conn, hangup_handler); } listen_handler(conn) /* called when listen completes */ { REQUEST_PACKET requ; receive_nowait(conn, &requ, sizeof(REQUEST_PACKET), receive_handler); } main() { for (;;) /* endless loop */ listen_nowait(anyone, listen_handler); }