简单的 xinetd 示例程序

通过 xinetd 的管理,可以按需启动某些“用完即走”的网络服务。实际上,xinetd 相当于网络层面的 wrapper, 应用程序只需要处理标准输入输出,网络层面的事情由 xinetd 代为处理即可。

以下是在 RHEL7 中实现的一个简单示例程序。

安装 xinetd 相关的包。

~]# yum install gcc xinetd telnet

编译一个 Hello world 标准输入输出程序。

tmp]# cat hello.c
#include <stdio.h>

int main()
{
    char str[100];
    printf("What's your name? \n");
    scanf("%99s", str);
    printf("Hello, %s\n", str);
    return 0;
}

tmp]# gcc -Wall -o hello hello.c

在 xinetd 中添加相应的配置。在这个示例中,希望客户端访问 9991 端口时,能访问到 hello 这个程序。

 ~]# cat /etc/xinetd.d/hello-server 
service hello-server
{
	protocol	= tcp
	disable		= no
	port		= 9991
	socket_type	= stream
	wait		= no
	user		= root
	server		= /tmp/hello
}

 ~]# cat /etc/services | grep hello-server
hello-server	9991/tcp		# xinetd test

重启 xinetd 服务,可以看到 xinetd 服务会监听 9991 端口。


 ~]# systemctl restart xinetd

 ~]# ss -tulnp | grep 9991
tcp    LISTEN     0      64       :::9991                 :::*                   users:(("xinetd",pid=12855,fd=5))

通过 telnet 连接到 9991 端口,即可访问到 hello 程序。

 ~]# telnet 127.0.0.1 9991
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
feichashao
What's your name? 
Hello, feichashao
Connection closed by foreign host.

如果对 xinetd 进行 strace, 可以看到实际上 xinetd 是创建了一个 socket,在运行 hello 时将标准输入输出重定向到这个 socket 中。

12855 13:47:09.443422 setsockopt(6, SOL_IPV6, IPV6_ADDRFORM, [2], 4) = 0 <0.000010>

12902 13:47:09.449971 getpeername(6, {sa_family=AF_INET, sin_port=htons(52860), sin_addr=inet_addr("127.0.0.1")}, [16]) = 0 <0.000009>
12902 13:47:09.450013 getsockname(6, {sa_family=AF_INET, sin_port=htons(9991), sin_addr=inet_addr("127.0.0.1")}, [16]) = 0 <0.000007>

12902 13:47:09.450641 dup2(6, 0)        = 0 <0.000008>
12902 13:47:09.450668 dup2(6, 1)        = 1 <0.000007>
12902 13:47:09.450693 dup2(6, 2)        = 2 <0.000007>

12902 13:47:09.450811 execve("/tmp/hello", ["hello"], ["LANG=en_US.UTF-8", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin", "EXTRAOPTIONS=", "XINETD_LANG=en_US", "REMOTE_HOST=::ffff:127.0.0.1"]) = 0 <0.000157>