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


ソースプログラム(server)
#include <stdio.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <string.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define	DATAFILE	"data"
#define	DELIMITS	" \t\n\r"

char	datavalue[256];

int	GetLineFromPeer(char *line, int hostsoc)
{
int	i;

for(i = 0 ; ; )
	{
	if(1 != read(hostsoc,line + i,1))
	  continue;
	else
		{
		i++;
		*(line + i) = (char)0;
		}

	if(((char)('\n')) == (*(line + i - 1)))
		return i;
	}
}

char	*GetKeywordData(char *key)
{
  FILE	*fp;
char	buff[256];

if((FILE *)NULL == (fp = fopen(DATAFILE,"r")))
	return (char *)NULL;

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,key))
	  {
		fclose(fp);
		strcpy(datavalue,pp);
		return datavalue;
	  }
	}

fclose(fp);
return (char *)NULL;
}

int	main()
{

  /**********deamon********/
  unsigned short port = 5683;
  int servsoc; 
  int hostsoc;
  
  struct sockaddr_in srcAddr;
  struct sockaddr_in dstAddr;
  int dstAddrSize = sizeof(dstAddr);
  
  memset(&srcAddr, 0, sizeof(srcAddr));
  srcAddr.sin_port = htons(port);
  srcAddr.sin_family = AF_INET;
  srcAddr.sin_addr.s_addr = htonl(INADDR_ANY);

  servsoc = socket(AF_INET, SOCK_STREAM, 0);
   
  bind(servsoc, (struct sockaddr *) &srcAddr, sizeof(srcAddr));

  listen(servsoc, 1);
  
  printf("now waiting for client connect\n");
  
  hostsoc = accept(servsoc, (struct sockaddr *) &dstAddr, &dstAddrSize);
  printf("Connected from %s\n", inet_ntoa(dstAddr.sin_addr));

  /**********daemon-ed**********/

char	RecvBuff[256];

for(;;)
	{
	char	*p;
	char	SendBuff[256];
	char	*pp;

	(void)GetLineFromPeer(RecvBuff, hostsoc);	/* Get 1 line from peer */
	

	if(((char)('=')) == *(RecvBuff))	/* If End Mark */
		{
		close(0);
		exit(0);
		}

	if((char *)NULL != (p = strchr(RecvBuff,'=')))
		{
		*p = (char)0;

		if((char *)NULL == (pp = GetKeywordData(RecvBuff)))
			sprintf(SendBuff,"%s=\n",RecvBuff);
		else
			sprintf(SendBuff,"%s=%s\n",RecvBuff,pp);

		(void)write(hostsoc,SendBuff,strlen(SendBuff));
		}
	}
}



ソースプログラム(server)
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define	SERVICE_NAME	"tcpinetd"
#define	PROTOCOL	"tcp"
#define	HOST_NAME	"localhost"

int	Connect()
{
int	SocketNumber;		/* Socket descripter */
struct	servent	*ServiceEntry;	/* service entry */
struct	hostent	*HostEntry;	/* host entry */
struct	sockaddr_in	sin;	/* Socket Entry */

/* Get Service Entry by Service-Name */

/******
 * if((struct servent *)NULL == (ServiceEntry =
 *	getservbyname(SERVICE_NAME,PROTOCOL)))
 *
 * {
 * printf("\7No service [%s].\n",SERVICE_NAME);
 * exit(1);
 * }
 * printf("%d\n",ServiceEntry->s_port);
 *****/

/* Get Host Entry by Host-Name */

/**********
 *if((struct hostent *)NULL == (HostEntry = gethostbyname(HOST_NAME)))
 *	{
 *	printf("\7No Hosts [%s].\n",HOST_NAME);
 *	exit(1);
 *	}
 *********/

/* Get Socket */

/******deamon*******/

HostEntry = gethostbyname("localhost");
  if(!HostEntry){
    printf("error:failed to serch the host\n");
    exit(1);
  }

/******deamon-ed******/

if(0 > (SocketNumber = (socket(AF_INET,SOCK_STREAM,0))))
	{
	printf("\7Cannot get Socket.\n");
	perror("\n");
	exit(1);
	}

/* Set protocol family name */
sin.sin_family = AF_INET;

/* Set Host Address */
bcopy(HostEntry->h_addr,&sin.sin_addr,HostEntry->h_length);

/* Set Port N.o. */
 sin.sin_port = 5683;  //ServiceEntry->s_port;

if(0 > connect(SocketNumber,(struct sockaddr *)(&sin),sizeof(sin)))
	{
	printf("\7Cannot Connect.\n");
	perror("\n");
	exit(1);
	}

return SocketNumber;
}

void	Disconnect(int SocketNumber)
{
close(SocketNumber);
}

void	SendData(int SocketNumber,char *line)
{
if(strlen(line) != write(SocketNumber,line,strlen(line)))
	{
	printf("\7Send Failed.\n");
	exit(1);
	}
}

int	RecvData(int SocketNumber,char *line)
{
int	i;

for(i = 0 ;;)
	{
	if(1 != read(SocketNumber,line + i,1))
		continue;
	else
		{
		i++;
		*(line + i) = (char)0;
	
		if(((char)('\n')) == *(line + i - 1))
			return i;
		}
	}
}

int	main()
{
int	Sock;
char	Key[256];
char	Data[256];
char	buff[256];

Sock = Connect();	/* Connect */
printf("Connected.\n");

for(;;)
	{
	char	*p;

	printf("Input Keyword = ");
	fflush(stdout);

	gets(Key);
	sprintf(buff,"%s=\n",Key);
	SendData(Sock,buff);		/* Send It ! */

	if(0 == strlen(Key))
		break;			/* If End Mark */

	/* ---- Waiting for Server response Here --- */

	(void)RecvData(Sock,buff);		/* Recv It ! */

	if((char *)NULL != (p = strchr(buff,'\n')))
		*p = (char)0;

	if((char *)NULL != (p = strchr(buff,'=')))
		p++;

	printf("Keyword = [%s] / Data = [%s]\n\n",Key,p);
	}

Disconnect(Sock);	/* Disconnect */
printf("Disocnnected.\n");
}



実行結果
[nw0553:~/inetd] j05053% ./client
Connected.
Input Keyword = warning: this program uses gets(), which is unsafe.
yama
Keyword = [yama] / Data = [kawa]

Input Keyword = xyz
Keyword = [xyz] / Data = [XYZ]

Input Keyword = 123
Keyword = [123] / Data = [456]

Input Keyword = xxxx
Keyword = [xxxx] / Data = [yyyy]

Input Keyword = shiro
Keyword = [shiro] / Data = [kuro]



実装上の違い

デーモン型は,常にクライアントの要求に答えるためサーバプログラム中にソケットを用意する必要があり, 通信速度が速いぶん,資源の消費が大きい.
inetdを使用する場合,呼び出しのたびにサーバを起動するため,資源を節約できる分,速度が劣る.


戻る