From owner-freebsd-hackers Wed Nov 13 11:49:56 1996 Return-Path: owner-hackers Received: (from root@localhost) by freefall.freebsd.org (8.7.5/8.7.3) id LAA09771 for hackers-outgoing; Wed, 13 Nov 1996 11:49:56 -0800 (PST) Received: from phaeton.artisoft.com (phaeton.Artisoft.COM [198.17.250.211]) by freefall.freebsd.org (8.7.5/8.7.3) with SMTP id LAA09756 for ; Wed, 13 Nov 1996 11:49:48 -0800 (PST) Received: (from terry@localhost) by phaeton.artisoft.com (8.6.11/8.6.9) id MAA22676; Wed, 13 Nov 1996 12:38:09 -0700 From: Terry Lambert Message-Id: <199611131938.MAA22676@phaeton.artisoft.com> Subject: Re: Programming technique for non-forking servers? To: stesin@gu.net (Andrew Stesin) Date: Wed, 13 Nov 1996 12:38:09 -0700 (MST) Cc: hackers@freebsd.org, squid-users@nlanr.net In-Reply-To: from "Andrew Stesin" at Nov 13, 96 12:32:33 pm X-Mailer: ELM [version 2.4 PL24] MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Sender: owner-hackers@freebsd.org X-Loop: FreeBSD.org Precedence: bulk > can anyone point me to some book, or URL(s), where the > programming technique for writing non-forking network server > daemons is described in details? with caveats, non-obvious > places... The Stevens books cover it... > Yes, there are sources, but I'd really like to read > some general theory on the subject. The general theory is that you change a blocking call into a non-blocking call + a context switch. In other words, it's state-machine based event driven multithreading. ,------> wait for packet | | | v | select() o-----------------------. | | socket A | socket B | v v | f(context A) f(context B) | \ / | \ / | \ / | \ / | \ / | v | o packet processing function f() | | | v | o any additional processing | | `------------------------' In addition, the packet may be a connect() request from a remote client; if so, you need to: 1) accept the connection to bind it to a local socket 2) add the socket to the list of fd's that the select is listening to 3) continue processing so the main loop looks like: /* * init */ create connect_socket for incoming connections post listen() on socket connect_socket init default fd_set default_read_mask to contain connect_socket set max_fd to connect_socket + 1 initialize context_list to NULL /* * main loop */ while( 1) { copy default_read_mask to real_read_mask select( max_fd, real_read_mask) /* * if we got here, a socket event has occurred; * real_read_mask will now contain the fd's * (sockets) which you must do processing on. */ /* check for incoming connections, first thing*/ if( FD_ISSET( connect_socket, &real_read_mask)) { /* clear so we don't hit it in processing loop*/ FD_CLR( connect_socket, &real_read_mask) /* generate default context for new connection*/ ctxp = new_context(); add_context( ctxp, context_list); ctxp->state = 0; ctxp->fd = accept( connect_socket) /* accept events on this context*/ FD_SET(ctxp->fd, &default_read_mask) } /* process all contexts which aren't incoming connections*/ for( ctxp = context_list; ctxp = ctxp->next) { if( FD_ISSET( ctxp->fd, &real_read_mask)) { handle_event( ctxp); } } } Terry Lambert terry@lambert.org --- Any opinions in this posting are my own and not those of my present or previous employers.