課題3:inetdを使用しないサーバプログラムの作成

サンプルプログラム(1)のサーバプログラム(server.c)はinetdから起動するものであるが、inetdを使用せずに同じ動作をするデーモン型のサーバプログラムを作成し、実行結果を示すとともに、inetdを使用するサーバプログラムとそうでないものとの実装上の違いを説明せよ。


serverプログラムのソース

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <unistd.h>

#define PORT 5524       /* Port Number */
#define SOCK_MAX 5      /* Max Socket */
#define UNUSED (-1)
#define	DATAFILE	"/Users/j05059/jikken2/tcpip/data.txt"
#define	DELIMITS	" \t\n\r"

char	datavalue[256];
    char buff[256];
char *Modification(char *str, int length);

int main()
{
    int s[SOCK_MAX + 1];
    int max = 0;
    int n = 0;
    int len;
    fd_set readfds;
    int clilen;
    struct sockaddr_in saddr;
    struct sockaddr_in caddr;
    char str[1024];
    int i, j;
    int msglen;
    char	*p;

    if ((s[0] = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
	perror("socket");
	exit(1);
	}
	
    bzero((char *)&saddr, sizeof(saddr));

    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = INADDR_ANY;
    saddr.sin_port = htons(PORT); 

    if ((bind(s[0], (struct sockaddr *)&saddr, sizeof(saddr))) == -1) {
	perror("bind");
	exit(1);
    }

    if ((listen(s[0], SOCK_MAX)) == -1) {
	perror("listen");
	exit(1);
    } 
    max = 1;

    while (1) {
	FD_ZERO(&readfds);
	printf("max: %d\n", max);
	for (i = 0; i < max; i++) {
	    if (s[i] != UNUSED) {
		FD_SET(s[i], &readfds);
	    }
	}
	if ((n = select(FD_SETSIZE, &readfds, NULL, NULL, NULL)) == -1) {
	    perror("select");
	    exit(1);
	}
	printf("select returns: %d\n", n);
	for (i = 1; i < max; i++) {
	    if (s[i] != UNUSED) {
		if (FD_ISSET(s[i], &readfds)) {
		    printf("s[%d] ready for reading\n", i);
		    if ((msglen = read(s[i], str, sizeof(str))) == -1) {
			/* Failed */
			perror("read");
		    } else if (msglen != 0) {
			/* Successed */
			printf("client[%d]: %s", i, str);
			/* Modified */
			Modification(str,msglen);  
			for (j = 1; j < max; j++) {
			    if (s[j] != UNUSED) {
				write(s[j], str, strlen(str));
			    }
			}
		    } else {
			printf("client[%d]: connection closed.\n", i);
			close(s[i]);
			s[i] = UNUSED;
		    }
		}
	    }
	}
		
	if (FD_ISSET(s[0], &readfds) != 0) {
	    printf("Accept New one.\n");
	    len = sizeof(caddr);
	    s[max] = accept(s[0], (struct sockaddr *)&caddr, &len);
	    printf("%d = accept()\n", s[max]);
	    if (s[max] == -1) {
		perror(NULL);
		exit(1);
	    }
	    if (max < SOCK_MAX) {
		printf("client accepted(%d).\n", max);
		max++;
	    } else {
		printf("refuse connection.\n");
		strcpy(str, "Server is too busy.\n");
		write(s[max], str, strlen(str));
		close(s[max]);
	    }
	}
    }
}

/* Return */
char *Modification(char *str, int length) {
  int i;
  FILE	*fp;
 int    n;
  if((FILE *)NULL == (fp = fopen(DATAFILE,"r")))
    return (char *)NULL;
     n=strlen(str);
     str[n-1]='\0';

  for(;;)
    {
      char	*p;
      char	*pp;
     
      fgets(buff,256,fp);
      
      if(feof(fp))
	break;
      
      if(ferror(fp))
	break;
      
      if((char *)NULL == (p = strtok(buff,DELIMITS)))
	continue;
      
      if((char *)NULL == (pp = strtok((char *)NULL,DELIMITS)))
	continue;
      
   
      
      
      if(0 == strcmp(p,str))
	{
	  fclose(fp);
	  strcpy(str,pp);
	  return str;
	}
    }
  
  fclose(fp);
  sprintf(str,"\n"); 
  return str;
}


clientプログラムのソース

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define PORT 5524 
#define HOST_NAME   "nw0559.st.ie.u-ryukyu.ac.jp"

main(int argc, char *argv[])
{
    struct sockaddr_in    addr;
    struct hostent *hp;
    int    fd;
    int    len;
    char   buf[1024];
    int    ret;

	/* Make Socket */
    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket");
        exit(1);
    }

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


    if ((hp = gethostbyname(HOST_NAME)) == NULL) {
	perror("No such host");
	exit(1);
    }
    bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(PORT);

    /* Connect to Server */
    if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0){
        perror("Server connected");
        exit(1);
    }
    /* Data Read */
    while (fgets(buf, 1024, stdin)) {
        write(fd, buf, 1024);
        ret = read(fd, buf, 1024);
	buf[ret] = '\0';
        printf("%s\n",buf);
    }
    close(fd);
    exit(0);
}


実行結果

20:08:/Users/j05059/jikken2/tcpip:%./client_noinetd
yama
kawa
123
456
xyz
XYZ


考察

inetdを使用するサーバプログラムとそうでないものとの実装上の違いは、inetdを用いたときは、クライアントが要求をおくると同時にサーバーが立ち上がり、要求に応答するとすぐに落ちる。そのため資源の消費は減少するが、サーバーの立ち上がりを待つ時間の分長くなるという欠点がある。
デーモン型の場合はクライアントの要求のたびににサーバープログラムを常駐させなければならない。そのため資源の消費が激しいが、応答時間が短い。


もどる