42.xinetd
xinetd
什么是xinetd
1、xinetd可以统一管理很多服务进程,它能够:
绑定、侦听、和接受来对自服务器每个端口的请求
有客户端访问时,调用相应的服务器程序响应
节约了系统内存资源
同时响应多个客户端的连接请求
2、Windows系统没有该功能
3、多数UNIX系统使用的是inetd实现相同的功能
配置文件解析
flags : 如果只指定NAMEINARGS,那么它就使参数和inetd一样地传递
type : 如果服务不在/etc/services中,则使用UNLISTED,否则可以忽略这一行
port : 如果type=UNILISTED,则在这里指定端口号
socket_type : 如果是TCP,使用stream;如果是UDP,使用dgram
protocol :指定TCP,还是UDP
wait : TCP设置为no。对于UDP,如果服务器连接远程主机并为不同客户端建立新的进程,则为no;如果UDP在它的端口上处理所有的信息包,
直到它被终止,则为yes
user : 指定程序的运行身份
server : 服务程序的完整路径
server_args :参数。为了和inetd兼容,flags设置为NAMEINARGS,则参数使用服务器名
编写xinetd程序
使用标准输入输出
1、当使用xinetd的时候,它通过两个方法传递socket:如文件描述符0和1
2、它们和文件描述符一样,分别代表标准输入和标准输出
3、因为标准输出sys.stdout默认是被缓冲的,所以为了实时性,需要使用到sys.stdout.flush()函数
4、通过这种方法,服务器端程序既可以当成网络服务器程序使用,也可以像普通的脚本程序一样执行
#!/usr/bin/env python
import sys
print 'Welcome.'
print 'Please enter a string: '
sys.stdout.flush()
line = sys.stdin.readline().strip()
print 'You enterd %d characters' % len(line)
执行结果: python ser.py
Welcome. Please enter a string: abc You enterd 3 characters
配置 xinetd 服务
编写 xinetd 服务配置文件,主要要求如下:
1、服务器监听在 0.0.0.0 的 51423 端口上
2、服务器采用 TCP 协议进行通信
3、服务器以 root 身份运行
4、服务器运行文件是/root/bin/exmaple.py
方案
前面所编写的服务器程序,都只能接受一个客户端的连接,如果超过一个客户端,后续的请求不得不排队等候。
使用超级守护进程 xinetd 是解决多客户端连接的一种方式。它能够绑定、侦听、和接受来对自服务器每个端口的请求,有客户端访问时,调用相应的服务器程序响应。
还能够同时响应多个客户端的连接请求。
基于 xinetd 超级守护进程的服务,需要在/etc/xinetd.d/目录下创建相关的服务器配置文件
步骤
实现此案例需要按照如下步骤进行。
步骤一:安装并配置 xinetd
RHEL6 操作系统默认没有安装 xinetd,首先安装
[root@py01 bin]# yum install -y xinetd
[root@py01 bin]# service xinetd start
[root@py01 bin]# chkconfig xinetd on
步骤二:创建服务器配置文件
[root@py01 bin]# vim /etc/xinetd.d/pyserver
service pyserver #起始语句块
{
flags = NAMEINARGS #使参数和 inetd 一样地传递
type = UNLISTED #如果服务不在/etc/services,指定为 UNLISTED
port = 51423 #指定服务端口号
socket_type = stream #使用 TCP 协议,则为 stream
protocol = tcp
wait = no
user = root
server = /root/bin/example.py #指定服务器程序位置
server_args = /root/bin/example.py
}
2. 使用标准输入输出搭建 TCP 服务器
编写 exmaple.py 服务器端程序,主要要求如下:
1、服务器采用 xinetd 的方式运行
2、服务器监听在 0.0.0.0 的 51423 端口上
3、收到客户端数据后,将其加上时间戳后回送给客户端
4、如果客户端发过来的字符全是空白字符,则终止与客户端的连接
5、采用标准输入输出的方式进行编写
方案
当使用 xinetd 的时候,它通过两个方法传递 socket:如文件描述符 0 和 1。相应的,调用 sys.stdin.readline()接收数据。
因为标准输出 sys.stdout 默认是被缓冲的,不会及时把信息显示在屏幕上,所以为了实时性,需要调用 sys.stdou.flush()。
实现此案例需要按照如下步骤进行。
步骤一:编写脚本
[root@py01 bin]# vim example.py
#!/usr/bin/env python
#coding:utf-8
import sys
import time
sys.stdout.write('Please enter a string:\n> ')
sys.stdout.flush()
while True:
line = sys.stdin.readline().strip()
if not line:
break
sys.stdout.write('[%s] %s\n> ' % (time.ctime(), line))
sys.stdout.flush()
步骤二:验证执行效果
[root@py01 bin]# telnet 127.0.0.1 51423
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Please enter a string:
> hello world!
[Mon Jul 6 18:49:54 2015] hello world!
> #此处直接回车,退出程序
Connection closed by foreign host.
[root@py01 bin]#
3. 使用 socket 对象搭建 TCP 服务器
编写 exmaple.py 服务器端程序,主要要求如下:
1、服务器采用 xinetd 的方式运行
2、服务器监听在 0.0.0.0 的 51423 端口上
3、收到客户端数据后,将其加上时间戳后回送给客户端
4、如果客户端发过来的字符全是空白字符,则终止与客户端的连接
5、采用 socket 对象的方式进行编写
方案
使用 socket“更像”网络服务器程序。因为客户端的请求首先要发送到超级守护进程xinetd,所以需要根据 xinetd 传递过来的文件描述符建立 socket 对象。
通过调用socket.fromfd()可以建立 socket 对象
实现此案例需要按照如下步骤进行。
步骤一:编写脚本
[root@py01 bin]# mv example.py example1.py #将实验 2 的服务器程序改名
root@py01 bin]# vim example.py #建立新的服务器程序
#!/usr/bin/env python
#coding:utf-8
import sys
import time
import socket
s = socket.fromfd(sys.stdin.fileno(), socket.AF_INET, socket.SOCK_STREAM)
s.sendall('Welcome!\n> ')
while True:
data = s.recv(4096).strip()
if not data:
break
s.sendall('[%s] %s\n> ' % (time.ctime(), data))
s.close()
步骤二:验证执行结果
[root@py01 bin]# telnet 127.0.0.1 51423
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Welcome!
> hello world!
[Mon Jul 6 19:03:02 2015] hello world!
> #此处直接输入回车,退出连接
Connection closed by foreign host.
例子:
step1:
yum -y install xinetd
yum -y install tftp-server
step2:
[root@host-192-168-3-6 day10]# vim /etc/xinetd.d/pyserv
service pyserv
{
flags = NAMEINARGS
type = UNLISTED
port = 12345
socket_type = stream
protocol = TCP
wait = no
user = root
server = /root/day10/example.py
server_args = /root/day10/example.py
}
step3:
/root/day10/example.py内容:
#!/usr/bin/env python
#coding:utf8
import sys
print "Welcome ."
print "Enter Line."
sys.stdout.flush()
line = sys.stdin.readline().strip()
sys.stdout.write("You entered %s chars" % len(line))
测试:
[root@host-192-168-3-6 ~]# chmod +x /root/day10/example.py
root@host-192-168-3-6 ~]# cd /root/day10/
[root@host-192-168-3-6 day10]# python example.py
Welcome .
Enter Line.
hello world!
You entered 12 chars
[root@host-192-168-3-6 day10]#
[root@host-192-168-3-6 day10]# systemctl restart xinetd
[root@host-192-168-3-6 day10]# netstat -tulnp| grep 12345
tcp6 0 0 :::12345 :::* LISTEN 3738/xinetd
[root@host-192-168-3-6 day10]#
[root@host-192-168-3-6 day10]# telnet 127.0.0.1 12345
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Welcome.
Enter Line.
agfasfasdfa
You entered 11 chars
Connection closed by foreign host.
[root@host-192-168-3-6 day10]#
修改/root/day10/example.py内容
#!/usr/bin/env python
#coding:utf8
import sys
import time
sys.stdout.write('>')
sys.stdout.flush()
while True:
data = sys.stdin.readline()
if not data.strip():
break
sys.stdout.write("[%s] %s>" %(time.ctime(),data))
sys.stdout.flush()
测试:
[root@host-192-168-3-6 day10]# ./example.py
>hello world
[Mon Jun 19 10:19:20 2017] hello world
>
修改/root/day10/example.py内容:
#!/usr/bin/env python
#coding:utf8
import sys
import time
import socket
s = socket.fromfd(sys.stdin.fileno(),socket.AF_INET,socket.SOCK_STREAM)
s.sendall("Welcome!\n")
s.send("you are connected from %s\n" % str(s.getpeername()))
s.send("Now: %s\n" % time.ctime())
测试:
[root@host-192-168-3-6 day10]# telnet 127.0.0.1 12345
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
Welcome!
you are connected from ('127.0.0.1', 51738)
Now: Mon Jun 19 10:51:18 2017
Connection closed by foreign host.
修改/root/day10/example.py内容:
#!/usr/bin/env python
#coding:utf8
import sys
import time
import socket
s = socket.fromfd(sys.stdin.fileno(),socket.AF_INET,socket.SOCK_STREAM)
while True:
data = s.recv(4096)
if not data.strip():
break
s.send("[%s] %s " % (time.ctime(),data))
s.close()
测试:
[root@host-192-168-3-6 day10]# telnet 127.0.0.1 12345
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
hello
[Mon Jun 19 10:54:12 2017] hello
world
[Mon Jun 19 10:54:16 2017] world