汎用サーバライブラリ

$Date: 2002/02/16 08:20:44 $

汎用のクライアント/サーバシステムのサーバ部のプログラム。

サーバライブラリのヘッダとAPI

    #ifndef _SERVER_H_
    #define _SERVER_H_

    //#ifdef NO_GETDTABLESIZE
    //#define MAXDTAB		_NFILE
    //#else
    //#define MAXDTAB		getdtablesize()
    //				/* max number of file descriptors */
    //				/* it returns 64 on SunOS 4.x & NEWS OS 3.3 */
    //				/* it returns 30 on SunOS 3.x & NEWS OS 2.2 */
    //				/* 20 is guaranteed on all machines */
    //#endif
    // Cygwinでこの値が256になってしまったので、小さい値に固定する。
    #define MAXDTAB 32

    #define MAXCLIENT	64	/* max number of clients */
                                    /* (must be larger than MAXDTAB-1) */
    #define	BUFSIZE		512	/* max size of a request */
    #define	MAXQUE		5

    extern int portnum;
    extern int server_debug;

サーバのメインルーチンの呼び出し
    typedef int ProcessFunc(int);
    void server(int portnum, ProcessFunc *func);
引数 | portnum | サーバのポート番号
func | サーバから呼び出される関数
返り値 | なし
備考 | -

    #endif

サーバプログラムソース

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include "server.h"

    int server_debug = 0;

    static int initsock;		// 要求待ちsocket
    static int clientfd[MAXCLIENT];	// 各クライアント用socket
    static int nclients = 0;

    static void error(char *s)
    {
    	perror(s);
    	exit(-1);
    }

    void server(int portnum, ProcessFunc *func)
    {
    	int i;
    	int len;
    	char value;
    	struct sockaddr_in sin;
    	struct sockaddr_in from;
    	struct servent *sp;

    	fd_set readfds, writefds, exceptfds;
    	fd_set getrfds();

    	bzero((char*)&sin, sizeof(sin));

    	sin.sin_family = AF_INET;
    	//sin.sin_addr.s_addr = htonl(INADDR_ANY);
    	sin.sin_addr.s_addr = INADDR_ANY;
    	sin.sin_port = htons(portnum);

    	if((initsock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
    		error("socket error; socket cannot be created");
    	value = 1;
            if (setsockopt(initsock, SOL_SOCKET, SO_REUSEADDR,
                   (char *)(&value), sizeof(int)) < 0)
                    error("setsockopt");
    	if(bind(initsock, (struct sockaddr *)&sin, sizeof(sin))< 0)
    		error("bind error; the socket is already used");
    	if(listen(initsock, MAXQUE) < 0)
    		error("listen error; something wrong happened with the socket");
    	if(server_debug) printf("file descriptor for initsock is %d\n", initsock);

    	FD_ZERO(&writefds);
    	FD_ZERO(&exceptfds);
    	for(;;){
    		FD_ZERO(&readfds);
    		FD_SET(initsock, &readfds);
    		for (i = 0; i < nclients; i ++)
    			FD_SET(clientfd[i], &readfds);
    		if (select(MAXDTAB, &readfds, &writefds, &exceptfds, NULL) < 0)
    			error("select error; something wrong happened with the socket");
    		if(server_debug) printf("select: read file descriptor is %08x\n", readfds);
    		if (FD_ISSET(initsock, &readfds)) {
    			len = sizeof(from);
    			if((clientfd[nclients++] = accept(initsock, &from, &len)) < 0) {
    				error("accept error; something wrong happened with the socket");
    			}
    			if(nclients >= MAXDTAB-3) {
    				write(clientfd[--nclients], "F", 1);
    				close(clientfd[nclients]);
    			}
    		}
    		for (i = 0; i < nclients; i ++){
    			if (FD_ISSET(clientfd[i], &readfds)) {
    				if ((*func)(clientfd[i]) < 0) {
    			  		/* -1 means client closed the connection */
    					close(clientfd[i]);
    					clientfd[i] = clientfd[nclients-1];
    					nclients--;
    				}
    			}
    		}
    	}
    }