用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 虚拟机