課題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を使用する場合,呼び出しのたびにサーバを起動するため,資源を節約できる分,速度が劣る.