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