UNIX下利用inetd daemon 管理应用系统的守护进程
中国银行西安市分行信息科技处 胡旋
在当今网际互连中 TCP/IP 已成为事实上的标准,大部分应用程序均采用C/S操作模式、TCP/IP编程并运行。即客户端向服务器发出请求,服务器运行守护进程,随时监听和捕捉客户端的请求并进行相应的处理。对于较大类型的应用系统,如银行综合业务处理系统,将产生各种类型的后台服务进程,这些进程均在无休止的等待,增加系统负载,耗费系统资源,并且管理起来也不方便。
UNIX操作系统为用户提供inetd daemon 进行网络服务管理。它将所有的后台应用程序置于它的管理之下,在客户端没有请求时,所有的后台应用程序都不启动,一旦客户端有特定的请求上来,它将根据/etc/services 和/etc/inetd.conf 文件描述的请求端口号和服务名调动相应的应用程序进行处理,而其它后台应用程序是不启动的。被启动的应用程序完成了特定任务后就终结自己的进程,这就减轻了系统负载,节约了系统资源,极大地提高了系统效率,是实现应用系统网络互连的一个实用工具。
inetd daemon 在开机时由/etc/rc.tcpip文件启动,一旦inetd daemon 启动即从 /etc/inetd.conf 文件中读取它的配置信息,然后在特定的套接字上监听连接请求,该文件的作用是告诉 inetd daemon 各端口号上的请求如何处理。即该服务采用何种套接字类型,是字节流还是数据报,采用什么协议(TCP/UDP),应用程序等待否,在监听套接字之前是否释放套接字,应用程序的名字、参数及路径等。整个流程可用下图表示:
inetd daemon 在运行中可通过SRC命令(startsrc stopsrc lssrc等)进行控制。所以,可以很方便地对后台应用程序进行管理。
下面简要介绍如何在inetd daemon 中增加一个新的后台处理程序,假定该程序是电话银行的后台处理程序tbankd。
1.修改 /etc/services 文件,增加新的应用程序的端口号和服务名。
服务名 端口号/网络类型
tbank 3000/tcp
2.修改 /etc/inetd.conf 配置文件,增加新的一行配置:
服务名套接字类型 采用的协议 等待否 用户名 应用程序及路径 参数
tbank stream tcp nowait root /u0/tbank/bin/tbankd
3.应用程序编程注意事项
服务器上的应用程序 tbankd 从标准输入 stdin 中读取客户端发来的请求数据,返回的处理信息也写入 stdin。
4.重新启动 inetd daemon
先用 stopsrc -s inetd 命令关闭 inetd daemon,
再用 startsrc -s inetd 命令启动.
或用refresh -s inetd 省去关闭启动过程,直接通知inetd daemon 配置文件已改变,启用新的配置文件。
5.查看inetd daemon 运行状况:
键入lssrc -a 后系统显示:
Subsystem Group PID Status
inetd tcpip 26912 active
表示 inetd daemon 已正常启动 进程号为 26912
6.inetd daemon 运行流程图 :
本地主机 远程主机 从标准输入
前台通信请求方 服务器方 接收请求
read(0)
创建套接字 后台处理程序一 处理
向标准输入
建立链接 inetd daemon 返回处理结果
write(0)
向服务器发出
请求数据报文 后台处理程序二 ...
.
阻塞等待服务器 .
返回数据报文 .
收到结果报文 后台处理程序N ...
其它处理
7.程序实例 :
该程序是一个实用的基本模型,用户可在此基础上开发出自己的应用程序。
[code:1:67a40bb2ce]/*client 客户端程序*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/times.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define HEADLEN 6
main(argc,argv)
int argc;
char ** argv;
{
int sockfd;
struct sockaddr_in serv_addr;/*存服务器方的地址*/
char info[4096],head[7];
int infolen;
int rc;
if (argc!=2)
{
fprintf(stderr,"client ipaddress\n");
exit(-1);
}
/*参数是服务器的IP地址*/
bzero((char *)&serv_addr, sizeof(serv_addr));
/*服务器地址变量清0*/
serv_addr.sin_family = AF_INET;
/*网络地址类型使用ARPA internet 地址*/
serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
/*服务器IP地址转换为长整型IP地址, 并赋予地址结构变量*/
serv_addr.sin_port=htons(6000);
/*与服务器相同的IP端口号, 经主机字节顺序到网络字节顺序的转换*/
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
/*创建TCP协议的字节流套接字*/
{
fprintf(stderr, "Client : Can not open stream socket\n");
exit(-1);
}
/*与服务进程建立连接*/
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
{
fprintf(stderr,"err connect ....\n");
exit(-1);
}
/*此时连接已建立, 可通过对套接字的读写实现通信*/
/*客户进程向服务进程发送请求信息*/
sprintf(info,"000026向服务器发出查询张三的请求");
infolen=strlen(info);
if ( (rc=write(sockfd, info, infolen)) == -1 )
fprintf(stderr, "TCPSend failed !!\n");
/*接受服务器返回的头信息*/
memset(head,0,sizeof(head));
if (( rc=read(sockfd, head, HEADLEN)) == -1
|| rc<HEADLEN
|| (infolen=atoi(head))<=0 )
{
fprintf(stderr, "read head failed rc:%d!!\n",rc);
exit(-1);
}
/*接受服务器返回的报文信息*/
memset(info,0,sizeof(info));
if ( (rc=read(sockfd, info, infolen)) == -1 )
fprintf(stderr, "TCPRecv failed !!\n");
/*客户进程接收服务进程返回的帐户信息*/
fprintf(stderr,"%s\n",info);
shutdown(sockfd, 2);
close(sockfd);
}
/*tbankd后台服务程序*/
#include <stdio.h>
#define HEADLEN 6
FILE *fp_log;
main(argc,argv)
int argc;
char ** argv;
{
char info[1024],head[7];
int infolen;
int rc;
char * send_info;
fp_log=fopen("/_tbank.log","a");
memset(head,0,sizeof(head));
/*接受客户机发来的头信息*/
if (( rc=read(0, head, HEADLEN)) == -1
|| rc<HEADLEN
|| (infolen=atoi(head))<=0 )
{
fprintf(fp_log, "read head failed rc:%d!!\n",rc);
exit(-1);
}
memset(info,0,sizeof(info));
if ((rc=read(0, info, infolen)) == -1 || rc<infolen )
/*接受客户机发来的信息*/
{
fprintf(fp_log, "read info failed !!\n");
exit(-1);
}
fprintf(fp_log,"收到的客户端的请求:%s\n",info);
send_info="000021张三当前余额1000.00元";
/*向客户机发送该帐户信息*/
infolen=strlen(send_info);
if ((rc=write(0, send_info, infolen) )== -1)
fprintf(fp_log, "TCPSend failed !!\n");
close(fp_log);
}[/code:1:67a40bb2ce]
【发表回复】【查看CU论坛原帖】【添加到收藏夹】【关闭】
延伸阅读
文章来源于领测软件测试网 https://www.ltesting.net/