用inetd装载应用程序

inetd是监视一些网络请求的守护进程,其根据网络请求来调用相应的服务进程来处理连接请求。

它可以为多种服务管理连接,当 inetd 接到连接时,它能够确定连接所需的程序,启动相应的进程,

并把 socket 交给它 (服务 socket 会作为程序的标准输入、 输出和错误输出描述符)。

使用 inetd 来运行那些负载不重的服务有助于降低系统负载,因为它不需要为每个服务都启动独立的服务程序。

 

使用inetd可以减免编写连接代码的过程,而且基本上可以把处理程序当成普通程序来编写。

 

下面先介绍inetd下的TCP服务器

首先,编写处理程序testd.c(这里用《TCP/IP高效编程 改善网络程序的44个技巧》的代码为例)

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
void main(void)
{
  int cnt = 0;
  char line[1024];

  setvbuf(stdout, NULL, _IOLBF, 0);

  while(fgets(line, sizeof(line), stdin) != NULL){
    printf("%3i: %s", ++cnt, line);
  } 

}

 

接着打开/etc/services文件

可以看到此系统的服务及其使用的端口号和协议

添加test            8000/tcp                        #remote line-numbering service

 

接着,在/etc/inetd.conf文件中添加,test stream tcp nowait chris /home/chris/testd testd

                (1)   (2)   (3)  (4)     (5)        (6)               (7)

(1)test:服务名字,即/etc/services所列的名字。

(2)stream:套接字类型(TCP:stream,UDP:dgram)

(3)tcp:使用的协议

(4)等待(wait)/不等待(nowait)标记:如果使用等待标记,在服务器终止之前,不会对套接字做其它操作。服务器终止时,恢复对连接或者数据包的监听。

                  通常TCP服务器使用nowait,UDP服务器使用wait。

(5)运行服务器时使用的用户名:此用户名必须在/etc/passwd中。

(6)服务器执行文件的绝对路径:这里使用的执行文件的绝对路径是/home/chris/testd

(7)向服务器传递的变元(从argv[0]开始):最多传递5个。

 

 

 

使用telnet对其进行测试:

 

另一个例子:

testd.c代码:

void main(void)
{
  int cnt = 0;
  char line[10];
  fgets(line, sizeof(line), stdin);  //通过标准输入接收客户端发来的消息
  //fscanf(stdin, "%s", line);
  fprintf(stdout, "%s", line);   //通过标准输出发送信息
}

客户端代码:

char buf[20] = "helloinetd";
void client(int fd)
{
  if(send(fd, buf, sizeof(buf), 0) <= 0)
    perror("send failed\n");
  memset(buf, 0, sizeof(buf));
  if(recv(fd, buf, sizeof(buf), 0) <= 0)
    perror("recv falied\n");
  printf("recv :%s\n", buf);
  return ;
}


void main(void)
{
  int fd;
  int res;

  struct sockaddr_in sock;
  bzero(&sock, sizeof(sock));
  sock.sin_family = AF_INET;
  sock.sin_port = htons(8000);
  sock.sin_addr.s_addr = inet_addr("127.0.0.1");

  fd = socket(AF_INET, SOCK_STREAM, 0);

  res = connect(fd, (struct sockaddr*)&sock, sizeof(sock));
  if(0 == res){
    printf("connect \n");
         client(fd);
    close(fd);
    exit(0);
  }

  close(fd);
  exit(0);

}

测试结果:

fgets(line, sizeof(line), stdin);    line缓冲区填不满时,客户端程序recv一直阻塞。   
fscanf遇到空格和换行时结束

 

 

UDP服务器:

同样,现在/etc/services中添加 testudp         8001/udp

在/etc/inetd.conf中添加testudp dgram udp wait chris /home/chris/testudpd testudpd

 

 

testudp.c代码(《TCP/IP高效编程 改善网络程序的44个技巧》中的代码):

#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <stdio.h>
void main(void)
{
  struct sockaddr_in peer;
  int rc;
  int len;
  int pidsz;
  char buf[120];

  pidsz = sprintf(buf, "%d:", getpid());
  len = sizeof(peer);
  rc = recvfrom(0, buf + pidsz, sizeof(buf) - pidsz, 0, (struct sockaddr*)&peer, &len);
  if(rc < 0)
    exit(1);
  sendto(1, buf, rc + pidsz, 0, (struct sockaddr*)&peer, len);
    exit(0);
}

 

udp客户端代码:

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

void main(void)
{
  struct sockaddr_in ser;
  int fd;
  int rc = 0;
  int len;
  char buf[20] = "hello udp inet";

  fd = socket(AF_INET, SOCK_DGRAM, 0);

  bzero(&ser, sizeof(ser));
  ser.sin_family = AF_INET;
  ser.sin_port = htons(8001);

  rc = sendto(fd, buf,strlen(buf), 0, (struct sockaddr*)&ser, sizeof(ser));
  if(rc < 0)
    perror("sendto failed");
  memset(buf, 0, sizeof(buf));

  len = sizeof(ser);

  rc = recvfrom(fd, buf, sizeof(buf) - 1, 0, (struct sockaddr*)&ser, &len);
  if(rc < 0)
    perror("recvfrom failed");

  buf[rc] = '\0';
  printf("%s\n",buf);

  exit(0);
}

测试结果:

3244:hello udp inet

 

以上均为简单的测试

测试环境:系统:Ubuntu 11.04    内核:Linux version 2.6.38-10-generic   虚拟机

posted on 2012-08-20 18:09  Chris-Lin  阅读(314)  评论(0编辑  收藏  举报

导航