SCO UNIX网络编程技术在监控进程中的应用
(南京通信工程学院计算机室 李清 210016)
---- 现在许多通信网监控系统都采用分级监控系统,如图1所示。上级监控中心接收下级监控中心的数据,并对下级监控中心实施监视和控制。每级监控中心都配有监控软件,主要有服务器软件和客户机软件。服务器软件主要包括数据处理软件和监控进程,下面就SCO UNIX环境下监控进程的编制进行说明。
---- 在SCO UNIX环境下编制监控进程通常采用两种方法,并发服务器和重复服务器处理。
---- 所谓并发服务器就是监控进程在接收到客户的一个连接请求时,便产生一个进程专门与其进行通信并作相应处理,其程序流程如图2。在此期间,由于每产生一个子进程,其便拥有与父进程同样的资源,该方式下,来一个请求便产生一个子进程,当申请连接的请求超过一定数目,产生的子进程数达到一定量时,系统运行很慢,几乎不能正常工作,因此并发服务器适于与客户间的短暂通信,通信完毕后即断开连接,结束相应子进程。
---- 在一些大型通信网监控系统中,通常要求客户机全天候与服务器相连接以保证能实时进行监控,而且这些监控系统中要监视(或请求服务)的客户机都比较多,按照并发服务器方式处理不能保证进程的正常运行。我们在SCO UNIX环境下测试,当连接的 Int initsockid,newsockid;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
if(listen(initsockid,5< 0)
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*阻塞*/
if(newsockid< 0)
error(“accept error”);
if(fork()==0/*子进程*/
{
close(initsockid);
do(newsockid);/*处理请求*/
exit(0);
}
close(newsockid);/*父进程*/
}
图2 并发服务器
int initsockid, newsockid
int flags=1;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
ioctl(sockid,FIONBIO,&flags);/*非阻塞*/
if(listen(initsockid,5< 0);
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*非阻塞*/
if(newsockid< 0)
error(“accept error”);
ioctl(newsockid,FIONBIO,&flags);/*非阻塞*/
do(newsockid);/*处理请求*/
close(newsockid);
}
图3 轮询与非阻塞方式相结合的重复服务器
---- 客户机超过10个时,系统运行异常,甚至出现死机。为了解决这个问题,采用第二种方法,即重复服务器处理,并将轮询和非阻塞方式相结合,其程序流程如图3
---- 所谓重复服务器处理就是当服务器接收到客户机的连接请求时,并不产生专门子进程,而是直接进行处理,这里便存在以下两种特殊情况:
---- (1)客户机只请求连接,并不进行数据传输。
---- (2)客户机请求连接后,进行大量数据传输。
---- 这两种情况在实时监控系统中有一个共同点是一旦连接上,除非客户断开连接,否则连接不能断开。
---- 在第一种情况下,若采用阻塞方式,则服务器一直等待已连接的客户机发送数据,这样,一方面不能及时接收其它客户机的连接请求,进行数据传输,进行实时性监控;另一方面,服务器处于闲置状态,造成资源浪费。而采用非阻塞方式则避免了上述情况,在非阻塞方式下,当连接的客户机没有数据传输时,服务器便转去处理别的客户机的请求。
---- 在第二种情况下,若服务器一旦与客户机相连后便接收其传来的数据,那么当客户机传输的数据量大时,接收和处理数据将占据一定时间,其间其它客户机就只能等待,不能得到及时处理。采用轮询法则可解决客户机长时间等待问题。
---- 轮询法的关键就是数据分段处理,每次以一个确定单位接收和处理客户机发来的数据,此单位大小取决于具体要连接的客户机数及传输数据报文的长度。为了保证服务器和客户机一次连接传输的数据能在同一次连接过程中完成(事实上也就是通过分配的同一个socket号进行接收),增加了一个辅助表。该表有客户机的IP地址,每次连接分配的socket号,以及其它信息。服务器每次接收到客户机连接请求后,便为其分配一个socket号,将其填入到辅助表对应的表项中,当下次轮询到此客户机时,服务器根据客户机的IP地址从辅助表中取出其对应的socket号,并根据此socket号进行数据接收和发送。辅助表中分配给客户机的socket号一直保留至接收到该客户机新的连接请求止。
---- 以下是一个具体实例。 #include < sys/types.h >
#include < sys/socket.h >
#include < netinet/in.h >
#include < stdio.h >
#include < errno.h >
#include < sys/ioctl.h >
#define MAX-LINKS 20 /* 所监控的客户机数目 */
#define PORTNUM 2330/*端口号*/
struct com-buf/*辅助表*/
{ struct m-table
{ char jkip[13];
char tz[5];
int msgsock;
int key;
} m-table[MAX-LINKS];
int skdb,sock;
}*comd;
int link-accept(s)
/**非阻塞方式接收客户机的连接请求 **/
int s; /* server socket */
{ int i, msgsock, flags=1; /* flags=1 非阻塞 */
struct sockaddr-in monitor;/*客户机 IP*/
if((msgsock=accept(s, (struct sockaddr)&monitor,
&sizeof(monitor)))< 0)/*非阻塞接收*/
{ perror(″no connections are pending″);
return 0;
}
for(i=0;i< MAX-LINKS;i++)
{ if(strcmp(comd- >m-table[i].
jkip,inet-ntoa(monitor.sin-addr))==0)
{ if (comd- >m-table[i].key==1)
close(comd- >m-table[i].msgsock);
ioctl(msgsock, FIONBIO,&flags); /* 置非阻塞方式 */
comd- >m-table[i].msgsock=msgsock
comd- >m-table[i].key=1
strcpy(a22, comd- >m-table[i].tz);
break;
}
}
return 1;
close(s);
}
void link-read()
/*非阻塞轮询方式接收客户机传来的数据*/
{ int msgsock, status, i;
char work[250];
for(i=0;i< MAX-LINKS;i++)
/* 轮询已连接的客户机 */
{ if (comd- >m-table[i].key==0) continue;
/*无连接则进行下一次轮询*/
msgsock=comd->m-table[i].msgsock;
/*从辅助表中取分配的socket号*/
bzero(work, sizeof(work));
/*数据接收的单位长度为sizeof(work)*/
if((status=recv(msgsock, work,
sizeof(work),0))< =0) /*非阻塞接收数据*/
{ if (status==0) errno=EHOSTDOWN;
status=RWError(msgsock);
continue; /* scan next link */
}
process(work);/*数据处理程序*/
}/** end of for (i=0;i< MAX-LINKS;i++) **/
}/** end of read all links **/
main ()
{ int sock, flags=1;
/* flags=1 置非阻塞标志 */
struct sockaddr-in serve;
/** server internet addr***/
if (initial () ==0)/*初始化辅助表*/
{ printf(″initial has error\n″);
exit(1);
}
sock=socket (AF-INET,SOCK-STREAM,0);
if (sock< 0)
{ perror(″can't create socket″);
exit (1);
}
comd- >sock=sock;/*服务器的socket号*/
bzero(&serve, sizeof(serve));
serve.sin-family=AF-INET;
serve.sin-addr.s-addr=INADDR-ANY;
serve.sin-port=htons (portnum);
if(bind(sock, (struct sockaddr
*)&serve, sizeof(serve))<0)
{ perror(″bind error″);
close(sock);
exit (1);
}
ioctl(sock,FIONBIO,&flags);/*置非阻塞方式*/
if (listen (sock, 5)< 0)
{ perror(″listen error″);
close(sock);
exit (1);
}
while (1)/*24小时实时监控*/
{
link-accept(sock);/*非阻塞连接*/
link-read();/*非阻塞轮询*/
} /* end while */
}/** end main **/
-
SCO UNIX网络编程技术在监控进程中的应用-sdccf-ChinaUnix博客
|
|
|
SCO UNIX网络编程技术在监控进程中的应用
(南京通信工程学院计算机室 李清 210016)
---- 现在许多通信网监控系统都采用分级监控系统,如图1所示。上级监控中心接收下级监控中心的数据,并对下级监控中心实施监视和控制。每级监控中心都配有监控软件,主要有服务器软件和客户机软件。服务器软件主要包括数据处理软件和监控进程,下面就SCO UNIX环境下监控进程的编制进行说明。
---- 在SCO UNIX环境下编制监控进程通常采用两种方法,并发服务器和重复服务器处理。
---- 所谓并发服务器就是监控进程在接收到客户的一个连接请求时,便产生一个进程专门与其进行通信并作相应处理,其程序流程如图2。在此期间,由于每产生一个子进程,其便拥有与父进程同样的资源,该方式下,来一个请求便产生一个子进程,当申请连接的请求超过一定数目,产生的子进程数达到一定量时,系统运行很慢,几乎不能正常工作,因此并发服务器适于与客户间的短暂通信,通信完毕后即断开连接,结束相应子进程。
---- 在一些大型通信网监控系统中,通常要求客户机全天候与服务器相连接以保证能实时进行监控,而且这些监控系统中要监视(或请求服务)的客户机都比较多,按照并发服务器方式处理不能保证进程的正常运行。我们在SCO UNIX环境下测试,当连接的 Int initsockid,newsockid;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
if(listen(initsockid,5< 0)
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*阻塞*/
if(newsockid< 0)
error(“accept error”);
if(fork()==0/*子进程*/
{
close(initsockid);
do(newsockid);/*处理请求*/
exit(0);
}
close(newsockid);/*父进程*/
}
图2 并发服务器
int initsockid, newsockid
int flags=1;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
ioctl(sockid,FIONBIO,&flags);/*非阻塞*/
if(listen(initsockid,5< 0);
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*非阻塞*/
if(newsockid< 0)
error(“accept error”);
ioctl(newsockid,FIONBIO,&flags);/*非阻塞*/
do(newsockid);/*处理请求*/
close(newsockid);
}
图3 轮询与非阻塞方式相结合的重复服务器
---- 客户机超过10个时,系统运行异常,甚至出现死机。为了解决这个问题,采用第二种方法,即重复服务器处理,并将轮询和非阻塞方式相结合,其程序流程如图3
---- 所谓重复服务器处理就是当服务器接收到客户机的连接请求时,并不产生专门子进程,而是直接进行处理,这里便存在以下两种特殊情况:
---- (1)客户机只请求连接,并不进行数据传输。
---- (2)客户机请求连接后,进行大量数据传输。
---- 这两种情况在实时监控系统中有一个共同点是一旦连接上,除非客户断开连接,否则连接不能断开。
---- 在第一种情况下,若采用阻塞方式,则服务器一直等待已连接的客户机发送数据,这样,一方面不能及时接收其它客户机的连接请求,进行数据传输,进行实时性监控;另一方面,服务器处于闲置状态,造成资源浪费。而采用非阻塞方式则避免了上述情况,在非阻塞方式下,当连接的客户机没有数据传输时,服务器便转去处理别的客户机的请求。
---- 在第二种情况下,若服务器一旦与客户机相连后便接收其传来的数据,那么当客户机传输的数据量大时,接收和处理数据将占据一定时间,其间其它客户机就只能等待,不能得到及时处理。采用轮询法则可解决客户机长时间等待问题。
---- 轮询法的关键就是数据分段处理,每次以一个确定单位接收和处理客户机发来的数据,此单位大小取决于具体要连接的客户机数及传输数据报文的长度。为了保证服务器和客户机一次连接传输的数据能在同一次连接过程中完成(事实上也就是通过分配的同一个socket号进行接收),增加了一个辅助表。该表有客户机的IP地址,每次连接分配的socket号,以及其它信息。服务器每次接收到客户机连接请求后,便为其分配一个socket号,将其填入到辅助表对应的表项中,当下次轮询到此客户机时,服务器根据客户机的IP地址从辅助表中取出其对应的socket号,并根据此socket号进行数据接收和发送。辅助表中分配给客户机的socket号一直保留至接收到该客户机新的连接请求止。
---- 以下是一个具体实例。 #include < sys/types.h >
#include < sys/socket.h >
#include < netinet/in.h >
#include < stdio.h >
#include < errno.h >
#include < sys/ioctl.h >
#define MAX-LINKS 20 /* 所监控的客户机数目 */
#define PORTNUM 2330/*端口号*/
struct com-buf/*辅助表*/
{ struct m-table
{ char jkip[13];
char tz[5];
int msgsock;
int key;
} m-table[MAX-LINKS];
int skdb,sock;
}*comd;
int link-accept(s)
/**非阻塞方式接收客户机的连接请求 **/
int s; /* server socket */
{ int i, msgsock, flags=1; /* flags=1 非阻塞 */
struct sockaddr-in monitor;/*客户机 IP*/
if((msgsock=accept(s, (struct sockaddr)&monitor,
&sizeof(monitor)))< 0)/*非阻塞接收*/
{ perror(″no connections are pending″);
return 0;
}
for(i=0;i< MAX-LINKS;i++)
{ if(strcmp(comd- >m-table[i].
jkip,inet-ntoa(monitor.sin-addr))==0)
{ if (comd- >m-table[i].key==1)
close(comd- >m-table[i].msgsock);
ioctl(msgsock, FIONBIO,&flags); /* 置非阻塞方式 */
comd- >m-table[i].msgsock=msgsock
comd- >m-table[i].key=1
strcpy(a22, comd- >m-table[i].tz);
break;
}
}
return 1;
close(s);
}
void link-read()
/*非阻塞轮询方式接收客户机传来的数据*/
{ int msgsock, status, i;
char work[250];
for(i=0;i< MAX-LINKS;i++)
/* 轮询已连接的客户机 */
{ if (comd- >m-table[i].key==0) continue;
/*无连接则进行下一次轮询*/
msgsock=comd->m-table[i].msgsock;
/*从辅助表中取分配的socket号*/
bzero(work, sizeof(work));
/*数据接收的单位长度为sizeof(work)*/
if((status=recv(msgsock, work,
sizeof(work),0))< =0) /*非阻塞接收数据*/
{ if (status==0) errno=EHOSTDOWN;
status=RWError(msgsock);
continue; /* scan next link */
}
process(work);/*数据处理程序*/
}/** end of for (i=0;i< MAX-LINKS;i++) **/
}/** end of read all links **/
main ()
{ int sock, flags=1;
/* flags=1 置非阻塞标志 */
struct sockaddr-in serve;
/** server internet addr***/
if (initial () ==0)/*初始化辅助表*/
{ printf(″initial has error\n″);
exit(1);
}
sock=socket (AF-INET,SOCK-STREAM,0);
if (sock< 0)
{ perror(″can't create socket″);
exit (1);
}
comd- >sock=sock;/*服务器的socket号*/
bzero(&serve, sizeof(serve));
serve.sin-family=AF-INET;
serve.sin-addr.s-addr=INADDR-ANY;
serve.sin-port=htons (portnum);
if(bind(sock, (struct sockaddr
*)&serve, sizeof(serve))<0)
{ perror(″bind error″);
close(sock);
exit (1);
}
ioctl(sock,FIONBIO,&flags);/*置非阻塞方式*/
if (listen (sock, 5)< 0)
{ perror(″listen error″);
close(sock);
exit (1);
}
while (1)/*24小时实时监控*/
{
link-accept(sock);/*非阻塞连接*/
link-read();/*非阻塞轮询*/
} /* end while */
}/** end main **/
-
SCO UNIX网络编程技术在监控进程中的应用-sdccf-ChinaUnix博客
|
|
|
SCO UNIX网络编程技术在监控进程中的应用
(南京通信工程学院计算机室 李清 210016)
---- 现在许多通信网监控系统都采用分级监控系统,如图1所示。上级监控中心接收下级监控中心的数据,并对下级监控中心实施监视和控制。每级监控中心都配有监控软件,主要有服务器软件和客户机软件。服务器软件主要包括数据处理软件和监控进程,下面就SCO UNIX环境下监控进程的编制进行说明。
---- 在SCO UNIX环境下编制监控进程通常采用两种方法,并发服务器和重复服务器处理。
---- 所谓并发服务器就是监控进程在接收到客户的一个连接请求时,便产生一个进程专门与其进行通信并作相应处理,其程序流程如图2。在此期间,由于每产生一个子进程,其便拥有与父进程同样的资源,该方式下,来一个请求便产生一个子进程,当申请连接的请求超过一定数目,产生的子进程数达到一定量时,系统运行很慢,几乎不能正常工作,因此并发服务器适于与客户间的短暂通信,通信完毕后即断开连接,结束相应子进程。
---- 在一些大型通信网监控系统中,通常要求客户机全天候与服务器相连接以保证能实时进行监控,而且这些监控系统中要监视(或请求服务)的客户机都比较多,按照并发服务器方式处理不能保证进程的正常运行。我们在SCO UNIX环境下测试,当连接的 Int initsockid,newsockid;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
if(listen(initsockid,5< 0)
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*阻塞*/
if(newsockid< 0)
error(“accept error”);
if(fork()==0/*子进程*/
{
close(initsockid);
do(newsockid);/*处理请求*/
exit(0);
}
close(newsockid);/*父进程*/
}
图2 并发服务器
int initsockid, newsockid
int flags=1;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
ioctl(sockid,FIONBIO,&flags);/*非阻塞*/
if(listen(initsockid,5< 0);
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*非阻塞*/
if(newsockid< 0)
error(“accept error”);
ioctl(newsockid,FIONBIO,&flags);/*非阻塞*/
do(newsockid);/*处理请求*/
close(newsockid);
}
图3 轮询与非阻塞方式相结合的重复服务器
---- 客户机超过10个时,系统运行异常,甚至出现死机。为了解决这个问题,采用第二种方法,即重复服务器处理,并将轮询和非阻塞方式相结合,其程序流程如图3
---- 所谓重复服务器处理就是当服务器接收到客户机的连接请求时,并不产生专门子进程,而是直接进行处理,这里便存在以下两种特殊情况:
---- (1)客户机只请求连接,并不进行数据传输。
---- (2)客户机请求连接后,进行大量数据传输。
---- 这两种情况在实时监控系统中有一个共同点是一旦连接上,除非客户断开连接,否则连接不能断开。
---- 在第一种情况下,若采用阻塞方式,则服务器一直等待已连接的客户机发送数据,这样,一方面不能及时接收其它客户机的连接请求,进行数据传输,进行实时性监控;另一方面,服务器处于闲置状态,造成资源浪费。而采用非阻塞方式则避免了上述情况,在非阻塞方式下,当连接的客户机没有数据传输时,服务器便转去处理别的客户机的请求。
---- 在第二种情况下,若服务器一旦与客户机相连后便接收其传来的数据,那么当客户机传输的数据量大时,接收和处理数据将占据一定时间,其间其它客户机就只能等待,不能得到及时处理。采用轮询法则可解决客户机长时间等待问题。
---- 轮询法的关键就是数据分段处理,每次以一个确定单位接收和处理客户机发来的数据,此单位大小取决于具体要连接的客户机数及传输数据报文的长度。为了保证服务器和客户机一次连接传输的数据能在同一次连接过程中完成(事实上也就是通过分配的同一个socket号进行接收),增加了一个辅助表。该表有客户机的IP地址,每次连接分配的socket号,以及其它信息。服务器每次接收到客户机连接请求后,便为其分配一个socket号,将其填入到辅助表对应的表项中,当下次轮询到此客户机时,服务器根据客户机的IP地址从辅助表中取出其对应的socket号,并根据此socket号进行数据接收和发送。辅助表中分配给客户机的socket号一直保留至接收到该客户机新的连接请求止。
---- 以下是一个具体实例。 #include < sys/types.h >
#include < sys/socket.h >
#include < netinet/in.h >
#include < stdio.h >
#include < errno.h >
#include < sys/ioctl.h >
#define MAX-LINKS 20 /* 所监控的客户机数目 */
#define PORTNUM 2330/*端口号*/
struct com-buf/*辅助表*/
{ struct m-table
{ char jkip[13];
char tz[5];
int msgsock;
int key;
} m-table[MAX-LINKS];
int skdb,sock;
}*comd;
int link-accept(s)
/**非阻塞方式接收客户机的连接请求 **/
int s; /* server socket */
{ int i, msgsock, flags=1; /* flags=1 非阻塞 */
struct sockaddr-in monitor;/*客户机 IP*/
if((msgsock=accept(s, (struct sockaddr)&monitor,
&sizeof(monitor)))< 0)/*非阻塞接收*/
{ perror(″no connections are pending″);
return 0;
}
for(i=0;i< MAX-LINKS;i++)
{ if(strcmp(comd- >m-table[i].
jkip,inet-ntoa(monitor.sin-addr))==0)
{ if (comd- >m-table[i].key==1)
close(comd- >m-table[i].msgsock);
ioctl(msgsock, FIONBIO,&flags); /* 置非阻塞方式 */
comd- >m-table[i].msgsock=msgsock
comd- >m-table[i].key=1
strcpy(a22, comd- >m-table[i].tz);
break;
}
}
return 1;
close(s);
}
void link-read()
/*非阻塞轮询方式接收客户机传来的数据*/
{ int msgsock, status, i;
char work[250];
for(i=0;i< MAX-LINKS;i++)
/* 轮询已连接的客户机 */
{ if (comd- >m-table[i].key==0) continue;
/*无连接则进行下一次轮询*/
msgsock=comd->m-table[i].msgsock;
/*从辅助表中取分配的socket号*/
bzero(work, sizeof(work));
/*数据接收的单位长度为sizeof(work)*/
if((status=recv(msgsock, work,
sizeof(work),0))< =0) /*非阻塞接收数据*/
{ if (status==0) errno=EHOSTDOWN;
status=RWError(msgsock);
continue; /* scan next link */
}
process(work);/*数据处理程序*/
}/** end of for (i=0;i< MAX-LINKS;i++) **/
}/** end of read all links **/
main ()
{ int sock, flags=1;
/* flags=1 置非阻塞标志 */
struct sockaddr-in serve;
/** server internet addr***/
if (initial () ==0)/*初始化辅助表*/
{ printf(″initial has error\n″);
exit(1);
}
sock=socket (AF-INET,SOCK-STREAM,0);
if (sock< 0)
{ perror(″can't create socket″);
exit (1);
}
comd- >sock=sock;/*服务器的socket号*/
bzero(&serve, sizeof(serve));
serve.sin-family=AF-INET;
serve.sin-addr.s-addr=INADDR-ANY;
serve.sin-port=htons (portnum);
if(bind(sock, (struct sockaddr
*)&serve, sizeof(serve))<0)
{ perror(″bind error″);
close(sock);
exit (1);
}
ioctl(sock,FIONBIO,&flags);/*置非阻塞方式*/
if (listen (sock, 5)< 0)
{ perror(″listen error″);
close(sock);
exit (1);
}
while (1)/*24小时实时监控*/
{
link-accept(sock);/*非阻塞连接*/
link-read();/*非阻塞轮询*/
} /* end while */
}/** end main **/
-
SCO UNIX网络编程技术在监控进程中的应用-sdccf-ChinaUnix博客
|
|
|
SCO UNIX网络编程技术在监控进程中的应用
(南京通信工程学院计算机室 李清 210016)
---- 现在许多通信网监控系统都采用分级监控系统,如图1所示。上级监控中心接收下级监控中心的数据,并对下级监控中心实施监视和控制。每级监控中心都配有监控软件,主要有服务器软件和客户机软件。服务器软件主要包括数据处理软件和监控进程,下面就SCO UNIX环境下监控进程的编制进行说明。
---- 在SCO UNIX环境下编制监控进程通常采用两种方法,并发服务器和重复服务器处理。
---- 所谓并发服务器就是监控进程在接收到客户的一个连接请求时,便产生一个进程专门与其进行通信并作相应处理,其程序流程如图2。在此期间,由于每产生一个子进程,其便拥有与父进程同样的资源,该方式下,来一个请求便产生一个子进程,当申请连接的请求超过一定数目,产生的子进程数达到一定量时,系统运行很慢,几乎不能正常工作,因此并发服务器适于与客户间的短暂通信,通信完毕后即断开连接,结束相应子进程。
---- 在一些大型通信网监控系统中,通常要求客户机全天候与服务器相连接以保证能实时进行监控,而且这些监控系统中要监视(或请求服务)的客户机都比较多,按照并发服务器方式处理不能保证进程的正常运行。我们在SCO UNIX环境下测试,当连接的 Int initsockid,newsockid;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
if(listen(initsockid,5< 0)
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*阻塞*/
if(newsockid< 0)
error(“accept error”);
if(fork()==0/*子进程*/
{
close(initsockid);
do(newsockid);/*处理请求*/
exit(0);
}
close(newsockid);/*父进程*/
}
图2 并发服务器
int initsockid, newsockid
int flags=1;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
ioctl(sockid,FIONBIO,&flags);/*非阻塞*/
if(listen(initsockid,5< 0);
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*非阻塞*/
if(newsockid< 0)
error(“accept error”);
ioctl(newsockid,FIONBIO,&flags);/*非阻塞*/
do(newsockid);/*处理请求*/
close(newsockid);
}
图3 轮询与非阻塞方式相结合的重复服务器
---- 客户机超过10个时,系统运行异常,甚至出现死机。为了解决这个问题,采用第二种方法,即重复服务器处理,并将轮询和非阻塞方式相结合,其程序流程如图3
---- 所谓重复服务器处理就是当服务器接收到客户机的连接请求时,并不产生专门子进程,而是直接进行处理,这里便存在以下两种特殊情况:
---- (1)客户机只请求连接,并不进行数据传输。
---- (2)客户机请求连接后,进行大量数据传输。
---- 这两种情况在实时监控系统中有一个共同点是一旦连接上,除非客户断开连接,否则连接不能断开。
---- 在第一种情况下,若采用阻塞方式,则服务器一直等待已连接的客户机发送数据,这样,一方面不能及时接收其它客户机的连接请求,进行数据传输,进行实时性监控;另一方面,服务器处于闲置状态,造成资源浪费。而采用非阻塞方式则避免了上述情况,在非阻塞方式下,当连接的客户机没有数据传输时,服务器便转去处理别的客户机的请求。
---- 在第二种情况下,若服务器一旦与客户机相连后便接收其传来的数据,那么当客户机传输的数据量大时,接收和处理数据将占据一定时间,其间其它客户机就只能等待,不能得到及时处理。采用轮询法则可解决客户机长时间等待问题。
---- 轮询法的关键就是数据分段处理,每次以一个确定单位接收和处理客户机发来的数据,此单位大小取决于具体要连接的客户机数及传输数据报文的长度。为了保证服务器和客户机一次连接传输的数据能在同一次连接过程中完成(事实上也就是通过分配的同一个socket号进行接收),增加了一个辅助表。该表有客户机的IP地址,每次连接分配的socket号,以及其它信息。服务器每次接收到客户机连接请求后,便为其分配一个socket号,将其填入到辅助表对应的表项中,当下次轮询到此客户机时,服务器根据客户机的IP地址从辅助表中取出其对应的socket号,并根据此socket号进行数据接收和发送。辅助表中分配给客户机的socket号一直保留至接收到该客户机新的连接请求止。
---- 以下是一个具体实例。 #include < sys/types.h >
#include < sys/socket.h >
#include < netinet/in.h >
#include < stdio.h >
#include < errno.h >
#include < sys/ioctl.h >
#define MAX-LINKS 20 /* 所监控的客户机数目 */
#define PORTNUM 2330/*端口号*/
struct com-buf/*辅助表*/
{ struct m-table
{ char jkip[13];
char tz[5];
int msgsock;
int key;
} m-table[MAX-LINKS];
int skdb,sock;
}*comd;
int link-accept(s)
/**非阻塞方式接收客户机的连接请求 **/
int s; /* server socket */
{ int i, msgsock, flags=1; /* flags=1 非阻塞 */
struct sockaddr-in monitor;/*客户机 IP*/
if((msgsock=accept(s, (struct sockaddr)&monitor,
&sizeof(monitor)))< 0)/*非阻塞接收*/
{ perror(″no connections are pending″);
return 0;
}
for(i=0;i< MAX-LINKS;i++)
{ if(strcmp(comd- >m-table[i].
jkip,inet-ntoa(monitor.sin-addr))==0)
{ if (comd- >m-table[i].key==1)
close(comd- >m-table[i].msgsock);
ioctl(msgsock, FIONBIO,&flags); /* 置非阻塞方式 */
comd- >m-table[i].msgsock=msgsock
comd- >m-table[i].key=1
strcpy(a22, comd- >m-table[i].tz);
break;
}
}
return 1;
close(s);
}
void link-read()
/*非阻塞轮询方式接收客户机传来的数据*/
{ int msgsock, status, i;
char work[250];
for(i=0;i< MAX-LINKS;i++)
/* 轮询已连接的客户机 */
{ if (comd- >m-table[i].key==0) continue;
/*无连接则进行下一次轮询*/
msgsock=comd->m-table[i].msgsock;
/*从辅助表中取分配的socket号*/
bzero(work, sizeof(work));
/*数据接收的单位长度为sizeof(work)*/
if((status=recv(msgsock, work,
sizeof(work),0))< =0) /*非阻塞接收数据*/
{ if (status==0) errno=EHOSTDOWN;
status=RWError(msgsock);
continue; /* scan next link */
}
process(work);/*数据处理程序*/
}/** end of for (i=0;i< MAX-LINKS;i++) **/
}/** end of read all links **/
main ()
{ int sock, flags=1;
/* flags=1 置非阻塞标志 */
struct sockaddr-in serve;
/** server internet addr***/
if (initial () ==0)/*初始化辅助表*/
{ printf(″initial has error\n″);
exit(1);
}
sock=socket (AF-INET,SOCK-STREAM,0);
if (sock< 0)
{ perror(″can't create socket″);
exit (1);
}
comd- >sock=sock;/*服务器的socket号*/
bzero(&serve, sizeof(serve));
serve.sin-family=AF-INET;
serve.sin-addr.s-addr=INADDR-ANY;
serve.sin-port=htons (portnum);
if(bind(sock, (struct sockaddr
*)&serve, sizeof(serve))<0)
{ perror(″bind error″);
close(sock);
exit (1);
}
ioctl(sock,FIONBIO,&flags);/*置非阻塞方式*/
if (listen (sock, 5)< 0)
{ perror(″listen error″);
close(sock);
exit (1);
}
while (1)/*24小时实时监控*/
{
link-accept(sock);/*非阻塞连接*/
link-read();/*非阻塞轮询*/
} /* end while */
}/** end main **/
-
SCO UNIX网络编程技术在监控进程中的应用-sdccf-ChinaUnix博客
|
|
|
SCO UNIX网络编程技术在监控进程中的应用
(南京通信工程学院计算机室 李清 210016)
---- 现在许多通信网监控系统都采用分级监控系统,如图1所示。上级监控中心接收下级监控中心的数据,并对下级监控中心实施监视和控制。每级监控中心都配有监控软件,主要有服务器软件和客户机软件。服务器软件主要包括数据处理软件和监控进程,下面就SCO UNIX环境下监控进程的编制进行说明。
---- 在SCO UNIX环境下编制监控进程通常采用两种方法,并发服务器和重复服务器处理。
---- 所谓并发服务器就是监控进程在接收到客户的一个连接请求时,便产生一个进程专门与其进行通信并作相应处理,其程序流程如图2。在此期间,由于每产生一个子进程,其便拥有与父进程同样的资源,该方式下,来一个请求便产生一个子进程,当申请连接的请求超过一定数目,产生的子进程数达到一定量时,系统运行很慢,几乎不能正常工作,因此并发服务器适于与客户间的短暂通信,通信完毕后即断开连接,结束相应子进程。
---- 在一些大型通信网监控系统中,通常要求客户机全天候与服务器相连接以保证能实时进行监控,而且这些监控系统中要监视(或请求服务)的客户机都比较多,按照并发服务器方式处理不能保证进程的正常运行。我们在SCO UNIX环境下测试,当连接的 Int initsockid,newsockid;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
if(listen(initsockid,5< 0)
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*阻塞*/
if(newsockid< 0)
error(“accept error”);
if(fork()==0/*子进程*/
{
close(initsockid);
do(newsockid);/*处理请求*/
exit(0);
}
close(newsockid);/*父进程*/
}
图2 并发服务器
int initsockid, newsockid
int flags=1;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
ioctl(sockid,FIONBIO,&flags);/*非阻塞*/
if(listen(initsockid,5< 0);
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*非阻塞*/
if(newsockid< 0)
error(“accept error”);
ioctl(newsockid,FIONBIO,&flags);/*非阻塞*/
do(newsockid);/*处理请求*/
close(newsockid);
}
图3 轮询与非阻塞方式相结合的重复服务器
---- 客户机超过10个时,系统运行异常,甚至出现死机。为了解决这个问题,采用第二种方法,即重复服务器处理,并将轮询和非阻塞方式相结合,其程序流程如图3
---- 所谓重复服务器处理就是当服务器接收到客户机的连接请求时,并不产生专门子进程,而是直接进行处理,这里便存在以下两种特殊情况:
---- (1)客户机只请求连接,并不进行数据传输。
---- (2)客户机请求连接后,进行大量数据传输。
---- 这两种情况在实时监控系统中有一个共同点是一旦连接上,除非客户断开连接,否则连接不能断开。
---- 在第一种情况下,若采用阻塞方式,则服务器一直等待已连接的客户机发送数据,这样,一方面不能及时接收其它客户机的连接请求,进行数据传输,进行实时性监控;另一方面,服务器处于闲置状态,造成资源浪费。而采用非阻塞方式则避免了上述情况,在非阻塞方式下,当连接的客户机没有数据传输时,服务器便转去处理别的客户机的请求。
---- 在第二种情况下,若服务器一旦与客户机相连后便接收其传来的数据,那么当客户机传输的数据量大时,接收和处理数据将占据一定时间,其间其它客户机就只能等待,不能得到及时处理。采用轮询法则可解决客户机长时间等待问题。
---- 轮询法的关键就是数据分段处理,每次以一个确定单位接收和处理客户机发来的数据,此单位大小取决于具体要连接的客户机数及传输数据报文的长度。为了保证服务器和客户机一次连接传输的数据能在同一次连接过程中完成(事实上也就是通过分配的同一个socket号进行接收),增加了一个辅助表。该表有客户机的IP地址,每次连接分配的socket号,以及其它信息。服务器每次接收到客户机连接请求后,便为其分配一个socket号,将其填入到辅助表对应的表项中,当下次轮询到此客户机时,服务器根据客户机的IP地址从辅助表中取出其对应的socket号,并根据此socket号进行数据接收和发送。辅助表中分配给客户机的socket号一直保留至接收到该客户机新的连接请求止。
---- 以下是一个具体实例。 #include < sys/types.h >
#include < sys/socket.h >
#include < netinet/in.h >
#include < stdio.h >
#include < errno.h >
#include < sys/ioctl.h >
#define MAX-LINKS 20 /* 所监控的客户机数目 */
#define PORTNUM 2330/*端口号*/
struct com-buf/*辅助表*/
{ struct m-table
{ char jkip[13];
char tz[5];
int msgsock;
int key;
} m-table[MAX-LINKS];
int skdb,sock;
}*comd;
int link-accept(s)
/**非阻塞方式接收客户机的连接请求 **/
int s; /* server socket */
{ int i, msgsock, flags=1; /* flags=1 非阻塞 */
struct sockaddr-in monitor;/*客户机 IP*/
if((msgsock=accept(s, (struct sockaddr)&monitor,
&sizeof(monitor)))< 0)/*非阻塞接收*/
{ perror(″no connections are pending″);
return 0;
}
for(i=0;i< MAX-LINKS;i++)
{ if(strcmp(comd- >m-table[i].
jkip,inet-ntoa(monitor.sin-addr))==0)
{ if (comd- >m-table[i].key==1)
close(comd- >m-table[i].msgsock);
ioctl(msgsock, FIONBIO,&flags); /* 置非阻塞方式 */
comd- >m-table[i].msgsock=msgsock
comd- >m-table[i].key=1
strcpy(a22, comd- >m-table[i].tz);
break;
}
}
return 1;
close(s);
}
void link-read()
/*非阻塞轮询方式接收客户机传来的数据*/
{ int msgsock, status, i;
char work[250];
for(i=0;i< MAX-LINKS;i++)
/* 轮询已连接的客户机 */
{ if (comd- >m-table[i].key==0) continue;
/*无连接则进行下一次轮询*/
msgsock=comd->m-table[i].msgsock;
/*从辅助表中取分配的socket号*/
bzero(work, sizeof(work));
/*数据接收的单位长度为sizeof(work)*/
if((status=recv(msgsock, work,
sizeof(work),0))< =0) /*非阻塞接收数据*/
{ if (status==0) errno=EHOSTDOWN;
status=RWError(msgsock);
continue; /* scan next link */
}
process(work);/*数据处理程序*/
}/** end of for (i=0;i< MAX-LINKS;i++) **/
}/** end of read all links **/
main ()
{ int sock, flags=1;
/* flags=1 置非阻塞标志 */
struct sockaddr-in serve;
/** server internet addr***/
if (initial () ==0)/*初始化辅助表*/
{ printf(″initial has error\n″);
exit(1);
}
sock=socket (AF-INET,SOCK-STREAM,0);
if (sock< 0)
{ perror(″can't create socket″);
exit (1);
}
comd- >sock=sock;/*服务器的socket号*/
bzero(&serve, sizeof(serve));
serve.sin-family=AF-INET;
serve.sin-addr.s-addr=INADDR-ANY;
serve.sin-port=htons (portnum);
if(bind(sock, (struct sockaddr
*)&serve, sizeof(serve))<0)
{ perror(″bind error″);
close(sock);
exit (1);
}
ioctl(sock,FIONBIO,&flags);/*置非阻塞方式*/
if (listen (sock, 5)< 0)
{ perror(″listen error″);
close(sock);
exit (1);
}
while (1)/*24小时实时监控*/
{
link-accept(sock);/*非阻塞连接*/
link-read();/*非阻塞轮询*/
} /* end while */
}/** end main **/
-
SCO UNIX网络编程技术在监控进程中的应用-sdccf-ChinaUnix博客
|
|
|
SCO UNIX网络编程技术在监控进程中的应用
(南京通信工程学院计算机室 李清 210016)
---- 现在许多通信网监控系统都采用分级监控系统,如图1所示。上级监控中心接收下级监控中心的数据,并对下级监控中心实施监视和控制。每级监控中心都配有监控软件,主要有服务器软件和客户机软件。服务器软件主要包括数据处理软件和监控进程,下面就SCO UNIX环境下监控进程的编制进行说明。
---- 在SCO UNIX环境下编制监控进程通常采用两种方法,并发服务器和重复服务器处理。
---- 所谓并发服务器就是监控进程在接收到客户的一个连接请求时,便产生一个进程专门与其进行通信并作相应处理,其程序流程如图2。在此期间,由于每产生一个子进程,其便拥有与父进程同样的资源,该方式下,来一个请求便产生一个子进程,当申请连接的请求超过一定数目,产生的子进程数达到一定量时,系统运行很慢,几乎不能正常工作,因此并发服务器适于与客户间的短暂通信,通信完毕后即断开连接,结束相应子进程。
---- 在一些大型通信网监控系统中,通常要求客户机全天候与服务器相连接以保证能实时进行监控,而且这些监控系统中要监视(或请求服务)的客户机都比较多,按照并发服务器方式处理不能保证进程的正常运行。我们在SCO UNIX环境下测试,当连接的 Int initsockid,newsockid;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
if(listen(initsockid,5< 0)
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*阻塞*/
if(newsockid< 0)
error(“accept error”);
if(fork()==0/*子进程*/
{
close(initsockid);
do(newsockid);/*处理请求*/
exit(0);
}
close(newsockid);/*父进程*/
}
图2 并发服务器
int initsockid, newsockid
int flags=1;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
ioctl(sockid,FIONBIO,&flags);/*非阻塞*/
if(listen(initsockid,5< 0);
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*非阻塞*/
if(newsockid< 0)
error(“accept error”);
ioctl(newsockid,FIONBIO,&flags);/*非阻塞*/
do(newsockid);/*处理请求*/
close(newsockid);
}
图3 轮询与非阻塞方式相结合的重复服务器
---- 客户机超过10个时,系统运行异常,甚至出现死机。为了解决这个问题,采用第二种方法,即重复服务器处理,并将轮询和非阻塞方式相结合,其程序流程如图3
---- 所谓重复服务器处理就是当服务器接收到客户机的连接请求时,并不产生专门子进程,而是直接进行处理,这里便存在以下两种特殊情况:
---- (1)客户机只请求连接,并不进行数据传输。
---- (2)客户机请求连接后,进行大量数据传输。
---- 这两种情况在实时监控系统中有一个共同点是一旦连接上,除非客户断开连接,否则连接不能断开。
---- 在第一种情况下,若采用阻塞方式,则服务器一直等待已连接的客户机发送数据,这样,一方面不能及时接收其它客户机的连接请求,进行数据传输,进行实时性监控;另一方面,服务器处于闲置状态,造成资源浪费。而采用非阻塞方式则避免了上述情况,在非阻塞方式下,当连接的客户机没有数据传输时,服务器便转去处理别的客户机的请求。
---- 在第二种情况下,若服务器一旦与客户机相连后便接收其传来的数据,那么当客户机传输的数据量大时,接收和处理数据将占据一定时间,其间其它客户机就只能等待,不能得到及时处理。采用轮询法则可解决客户机长时间等待问题。
---- 轮询法的关键就是数据分段处理,每次以一个确定单位接收和处理客户机发来的数据,此单位大小取决于具体要连接的客户机数及传输数据报文的长度。为了保证服务器和客户机一次连接传输的数据能在同一次连接过程中完成(事实上也就是通过分配的同一个socket号进行接收),增加了一个辅助表。该表有客户机的IP地址,每次连接分配的socket号,以及其它信息。服务器每次接收到客户机连接请求后,便为其分配一个socket号,将其填入到辅助表对应的表项中,当下次轮询到此客户机时,服务器根据客户机的IP地址从辅助表中取出其对应的socket号,并根据此socket号进行数据接收和发送。辅助表中分配给客户机的socket号一直保留至接收到该客户机新的连接请求止。
---- 以下是一个具体实例。 #include < sys/types.h >
#include < sys/socket.h >
#include < netinet/in.h >
#include < stdio.h >
#include < errno.h >
#include < sys/ioctl.h >
#define MAX-LINKS 20 /* 所监控的客户机数目 */
#define PORTNUM 2330/*端口号*/
struct com-buf/*辅助表*/
{ struct m-table
{ char jkip[13];
char tz[5];
int msgsock;
int key;
} m-table[MAX-LINKS];
int skdb,sock;
}*comd;
int link-accept(s)
/**非阻塞方式接收客户机的连接请求 **/
int s; /* server socket */
{ int i, msgsock, flags=1; /* flags=1 非阻塞 */
struct sockaddr-in monitor;/*客户机 IP*/
if((msgsock=accept(s, (struct sockaddr)&monitor,
&sizeof(monitor)))< 0)/*非阻塞接收*/
{ perror(″no connections are pending″);
return 0;
}
for(i=0;i< MAX-LINKS;i++)
{ if(strcmp(comd- >m-table[i].
jkip,inet-ntoa(monitor.sin-addr))==0)
{ if (comd- >m-table[i].key==1)
close(comd- >m-table[i].msgsock);
ioctl(msgsock, FIONBIO,&flags); /* 置非阻塞方式 */
comd- >m-table[i].msgsock=msgsock
comd- >m-table[i].key=1
strcpy(a22, comd- >m-table[i].tz);
break;
}
}
return 1;
close(s);
}
void link-read()
/*非阻塞轮询方式接收客户机传来的数据*/
{ int msgsock, status, i;
char work[250];
for(i=0;i< MAX-LINKS;i++)
/* 轮询已连接的客户机 */
{ if (comd- >m-table[i].key==0) continue;
/*无连接则进行下一次轮询*/
msgsock=comd->m-table[i].msgsock;
/*从辅助表中取分配的socket号*/
bzero(work, sizeof(work));
/*数据接收的单位长度为sizeof(work)*/
if((status=recv(msgsock, work,
sizeof(work),0))< =0) /*非阻塞接收数据*/
{ if (status==0) errno=EHOSTDOWN;
status=RWError(msgsock);
continue; /* scan next link */
}
process(work);/*数据处理程序*/
}/** end of for (i=0;i< MAX-LINKS;i++) **/
}/** end of read all links **/
main ()
{ int sock, flags=1;
/* flags=1 置非阻塞标志 */
struct sockaddr-in serve;
/** server internet addr***/
if (initial () ==0)/*初始化辅助表*/
{ printf(″initial has error\n″);
exit(1);
}
sock=socket (AF-INET,SOCK-STREAM,0);
if (sock< 0)
{ perror(″can't create socket″);
exit (1);
}
comd- >sock=sock;/*服务器的socket号*/
bzero(&serve, sizeof(serve));
serve.sin-family=AF-INET;
serve.sin-addr.s-addr=INADDR-ANY;
serve.sin-port=htons (portnum);
if(bind(sock, (struct sockaddr
*)&serve, sizeof(serve))<0)
{ perror(″bind error″);
close(sock);
exit (1);
}
ioctl(sock,FIONBIO,&flags);/*置非阻塞方式*/
if (listen (sock, 5)< 0)
{ perror(″listen error″);
close(sock);
exit (1);
}
while (1)/*24小时实时监控*/
{
link-accept(sock);/*非阻塞连接*/
link-read();/*非阻塞轮询*/
} /* end while */
}/** end main **/
-
SCO UNIX网络编程技术在监控进程中的应用-sdccf-ChinaUnix博客
|
|
|
SCO UNIX网络编程技术在监控进程中的应用
(南京通信工程学院计算机室 李清 210016)
---- 现在许多通信网监控系统都采用分级监控系统,如图1所示。上级监控中心接收下级监控中心的数据,并对下级监控中心实施监视和控制。每级监控中心都配有监控软件,主要有服务器软件和客户机软件。服务器软件主要包括数据处理软件和监控进程,下面就SCO UNIX环境下监控进程的编制进行说明。
---- 在SCO UNIX环境下编制监控进程通常采用两种方法,并发服务器和重复服务器处理。
---- 所谓并发服务器就是监控进程在接收到客户的一个连接请求时,便产生一个进程专门与其进行通信并作相应处理,其程序流程如图2。在此期间,由于每产生一个子进程,其便拥有与父进程同样的资源,该方式下,来一个请求便产生一个子进程,当申请连接的请求超过一定数目,产生的子进程数达到一定量时,系统运行很慢,几乎不能正常工作,因此并发服务器适于与客户间的短暂通信,通信完毕后即断开连接,结束相应子进程。
---- 在一些大型通信网监控系统中,通常要求客户机全天候与服务器相连接以保证能实时进行监控,而且这些监控系统中要监视(或请求服务)的客户机都比较多,按照并发服务器方式处理不能保证进程的正常运行。我们在SCO UNIX环境下测试,当连接的 Int initsockid,newsockid;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
if(listen(initsockid,5< 0)
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*阻塞*/
if(newsockid< 0)
error(“accept error”);
if(fork()==0/*子进程*/
{
close(initsockid);
do(newsockid);/*处理请求*/
exit(0);
}
close(newsockid);/*父进程*/
}
图2 并发服务器
int initsockid, newsockid
int flags=1;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
ioctl(sockid,FIONBIO,&flags);/*非阻塞*/
if(listen(initsockid,5< 0);
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*非阻塞*/
if(newsockid< 0)
error(“accept error”);
ioctl(newsockid,FIONBIO,&flags);/*非阻塞*/
do(newsockid);/*处理请求*/
close(newsockid);
}
图3 轮询与非阻塞方式相结合的重复服务器
---- 客户机超过10个时,系统运行异常,甚至出现死机。为了解决这个问题,采用第二种方法,即重复服务器处理,并将轮询和非阻塞方式相结合,其程序流程如图3
---- 所谓重复服务器处理就是当服务器接收到客户机的连接请求时,并不产生专门子进程,而是直接进行处理,这里便存在以下两种特殊情况:
---- (1)客户机只请求连接,并不进行数据传输。
---- (2)客户机请求连接后,进行大量数据传输。
---- 这两种情况在实时监控系统中有一个共同点是一旦连接上,除非客户断开连接,否则连接不能断开。
---- 在第一种情况下,若采用阻塞方式,则服务器一直等待已连接的客户机发送数据,这样,一方面不能及时接收其它客户机的连接请求,进行数据传输,进行实时性监控;另一方面,服务器处于闲置状态,造成资源浪费。而采用非阻塞方式则避免了上述情况,在非阻塞方式下,当连接的客户机没有数据传输时,服务器便转去处理别的客户机的请求。
---- 在第二种情况下,若服务器一旦与客户机相连后便接收其传来的数据,那么当客户机传输的数据量大时,接收和处理数据将占据一定时间,其间其它客户机就只能等待,不能得到及时处理。采用轮询法则可解决客户机长时间等待问题。
---- 轮询法的关键就是数据分段处理,每次以一个确定单位接收和处理客户机发来的数据,此单位大小取决于具体要连接的客户机数及传输数据报文的长度。为了保证服务器和客户机一次连接传输的数据能在同一次连接过程中完成(事实上也就是通过分配的同一个socket号进行接收),增加了一个辅助表。该表有客户机的IP地址,每次连接分配的socket号,以及其它信息。服务器每次接收到客户机连接请求后,便为其分配一个socket号,将其填入到辅助表对应的表项中,当下次轮询到此客户机时,服务器根据客户机的IP地址从辅助表中取出其对应的socket号,并根据此socket号进行数据接收和发送。辅助表中分配给客户机的socket号一直保留至接收到该客户机新的连接请求止。
---- 以下是一个具体实例。 #include < sys/types.h >
#include < sys/socket.h >
#include < netinet/in.h >
#include < stdio.h >
#include < errno.h >
#include < sys/ioctl.h >
#define MAX-LINKS 20 /* 所监控的客户机数目 */
#define PORTNUM 2330/*端口号*/
struct com-buf/*辅助表*/
{ struct m-table
{ char jkip[13];
char tz[5];
int msgsock;
int key;
} m-table[MAX-LINKS];
int skdb,sock;
}*comd;
int link-accept(s)
/**非阻塞方式接收客户机的连接请求 **/
int s; /* server socket */
{ int i, msgsock, flags=1; /* flags=1 非阻塞 */
struct sockaddr-in monitor;/*客户机 IP*/
if((msgsock=accept(s, (struct sockaddr)&monitor,
&sizeof(monitor)))< 0)/*非阻塞接收*/
{ perror(″no connections are pending″);
return 0;
}
for(i=0;i< MAX-LINKS;i++)
{ if(strcmp(comd- >m-table[i].
jkip,inet-ntoa(monitor.sin-addr))==0)
{ if (comd- >m-table[i].key==1)
close(comd- >m-table[i].msgsock);
ioctl(msgsock, FIONBIO,&flags); /* 置非阻塞方式 */
comd- >m-table[i].msgsock=msgsock
comd- >m-table[i].key=1
strcpy(a22, comd- >m-table[i].tz);
break;
}
}
return 1;
close(s);
}
void link-read()
/*非阻塞轮询方式接收客户机传来的数据*/
{ int msgsock, status, i;
char work[250];
for(i=0;i< MAX-LINKS;i++)
/* 轮询已连接的客户机 */
{ if (comd- >m-table[i].key==0) continue;
/*无连接则进行下一次轮询*/
msgsock=comd->m-table[i].msgsock;
/*从辅助表中取分配的socket号*/
bzero(work, sizeof(work));
/*数据接收的单位长度为sizeof(work)*/
if((status=recv(msgsock, work,
sizeof(work),0))< =0) /*非阻塞接收数据*/
{ if (status==0) errno=EHOSTDOWN;
status=RWError(msgsock);
continue; /* scan next link */
}
process(work);/*数据处理程序*/
}/** end of for (i=0;i< MAX-LINKS;i++) **/
}/** end of read all links **/
main ()
{ int sock, flags=1;
/* flags=1 置非阻塞标志 */
struct sockaddr-in serve;
/** server internet addr***/
if (initial () ==0)/*初始化辅助表*/
{ printf(″initial has error\n″);
exit(1);
}
sock=socket (AF-INET,SOCK-STREAM,0);
if (sock< 0)
{ perror(″can't create socket″);
exit (1);
}
comd- >sock=sock;/*服务器的socket号*/
bzero(&serve, sizeof(serve));
serve.sin-family=AF-INET;
serve.sin-addr.s-addr=INADDR-ANY;
serve.sin-port=htons (portnum);
if(bind(sock, (struct sockaddr
*)&serve, sizeof(serve))<0)
{ perror(″bind error″);
close(sock);
exit (1);
}
ioctl(sock,FIONBIO,&flags);/*置非阻塞方式*/
if (listen (sock, 5)< 0)
{ perror(″listen error″);
close(sock);
exit (1);
}
while (1)/*24小时实时监控*/
{
link-accept(sock);/*非阻塞连接*/
link-read();/*非阻塞轮询*/
} /* end while */
}/** end main **/
-
SCO UNIX网络编程技术在监控进程中的应用-sdccf-ChinaUnix博客
|
|
|
SCO UNIX网络编程技术在监控进程中的应用
(南京通信工程学院计算机室 李清 210016)
---- 现在许多通信网监控系统都采用分级监控系统,如图1所示。上级监控中心接收下级监控中心的数据,并对下级监控中心实施监视和控制。每级监控中心都配有监控软件,主要有服务器软件和客户机软件。服务器软件主要包括数据处理软件和监控进程,下面就SCO UNIX环境下监控进程的编制进行说明。
---- 在SCO UNIX环境下编制监控进程通常采用两种方法,并发服务器和重复服务器处理。
---- 所谓并发服务器就是监控进程在接收到客户的一个连接请求时,便产生一个进程专门与其进行通信并作相应处理,其程序流程如图2。在此期间,由于每产生一个子进程,其便拥有与父进程同样的资源,该方式下,来一个请求便产生一个子进程,当申请连接的请求超过一定数目,产生的子进程数达到一定量时,系统运行很慢,几乎不能正常工作,因此并发服务器适于与客户间的短暂通信,通信完毕后即断开连接,结束相应子进程。
---- 在一些大型通信网监控系统中,通常要求客户机全天候与服务器相连接以保证能实时进行监控,而且这些监控系统中要监视(或请求服务)的客户机都比较多,按照并发服务器方式处理不能保证进程的正常运行。我们在SCO UNIX环境下测试,当连接的 Int initsockid,newsockid;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
if(listen(initsockid,5< 0)
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*阻塞*/
if(newsockid< 0)
error(“accept error”);
if(fork()==0/*子进程*/
{
close(initsockid);
do(newsockid);/*处理请求*/
exit(0);
}
close(newsockid);/*父进程*/
}
图2 并发服务器
int initsockid, newsockid
int flags=1;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
ioctl(sockid,FIONBIO,&flags);/*非阻塞*/
if(listen(initsockid,5< 0);
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*非阻塞*/
if(newsockid< 0)
error(“accept error”);
ioctl(newsockid,FIONBIO,&flags);/*非阻塞*/
do(newsockid);/*处理请求*/
close(newsockid);
}
图3 轮询与非阻塞方式相结合的重复服务器
---- 客户机超过10个时,系统运行异常,甚至出现死机。为了解决这个问题,采用第二种方法,即重复服务器处理,并将轮询和非阻塞方式相结合,其程序流程如图3
---- 所谓重复服务器处理就是当服务器接收到客户机的连接请求时,并不产生专门子进程,而是直接进行处理,这里便存在以下两种特殊情况:
---- (1)客户机只请求连接,并不进行数据传输。
---- (2)客户机请求连接后,进行大量数据传输。
---- 这两种情况在实时监控系统中有一个共同点是一旦连接上,除非客户断开连接,否则连接不能断开。
---- 在第一种情况下,若采用阻塞方式,则服务器一直等待已连接的客户机发送数据,这样,一方面不能及时接收其它客户机的连接请求,进行数据传输,进行实时性监控;另一方面,服务器处于闲置状态,造成资源浪费。而采用非阻塞方式则避免了上述情况,在非阻塞方式下,当连接的客户机没有数据传输时,服务器便转去处理别的客户机的请求。
---- 在第二种情况下,若服务器一旦与客户机相连后便接收其传来的数据,那么当客户机传输的数据量大时,接收和处理数据将占据一定时间,其间其它客户机就只能等待,不能得到及时处理。采用轮询法则可解决客户机长时间等待问题。
---- 轮询法的关键就是数据分段处理,每次以一个确定单位接收和处理客户机发来的数据,此单位大小取决于具体要连接的客户机数及传输数据报文的长度。为了保证服务器和客户机一次连接传输的数据能在同一次连接过程中完成(事实上也就是通过分配的同一个socket号进行接收),增加了一个辅助表。该表有客户机的IP地址,每次连接分配的socket号,以及其它信息。服务器每次接收到客户机连接请求后,便为其分配一个socket号,将其填入到辅助表对应的表项中,当下次轮询到此客户机时,服务器根据客户机的IP地址从辅助表中取出其对应的socket号,并根据此socket号进行数据接收和发送。辅助表中分配给客户机的socket号一直保留至接收到该客户机新的连接请求止。
---- 以下是一个具体实例。 #include < sys/types.h >
#include < sys/socket.h >
#include < netinet/in.h >
#include < stdio.h >
#include < errno.h >
#include < sys/ioctl.h >
#define MAX-LINKS 20 /* 所监控的客户机数目 */
#define PORTNUM 2330/*端口号*/
struct com-buf/*辅助表*/
{ struct m-table
{ char jkip[13];
char tz[5];
int msgsock;
int key;
} m-table[MAX-LINKS];
int skdb,sock;
}*comd;
int link-accept(s)
/**非阻塞方式接收客户机的连接请求 **/
int s; /* server socket */
{ int i, msgsock, flags=1; /* flags=1 非阻塞 */
struct sockaddr-in monitor;/*客户机 IP*/
if((msgsock=accept(s, (struct sockaddr)&monitor,
&sizeof(monitor)))< 0)/*非阻塞接收*/
{ perror(″no connections are pending″);
return 0;
}
for(i=0;i< MAX-LINKS;i++)
{ if(strcmp(comd- >m-table[i].
jkip,inet-ntoa(monitor.sin-addr))==0)
{ if (comd- >m-table[i].key==1)
close(comd- >m-table[i].msgsock);
ioctl(msgsock, FIONBIO,&flags); /* 置非阻塞方式 */
comd- >m-table[i].msgsock=msgsock
comd- >m-table[i].key=1
strcpy(a22, comd- >m-table[i].tz);
break;
}
}
return 1;
close(s);
}
void link-read()
/*非阻塞轮询方式接收客户机传来的数据*/
{ int msgsock, status, i;
char work[250];
for(i=0;i< MAX-LINKS;i++)
/* 轮询已连接的客户机 */
{ if (comd- >m-table[i].key==0) continue;
/*无连接则进行下一次轮询*/
msgsock=comd->m-table[i].msgsock;
/*从辅助表中取分配的socket号*/
bzero(work, sizeof(work));
/*数据接收的单位长度为sizeof(work)*/
if((status=recv(msgsock, work,
sizeof(work),0))< =0) /*非阻塞接收数据*/
{ if (status==0) errno=EHOSTDOWN;
status=RWError(msgsock);
continue; /* scan next link */
}
process(work);/*数据处理程序*/
}/** end of for (i=0;i< MAX-LINKS;i++) **/
}/** end of read all links **/
main ()
{ int sock, flags=1;
/* flags=1 置非阻塞标志 */
struct sockaddr-in serve;
/** server internet addr***/
if (initial () ==0)/*初始化辅助表*/
{ printf(″initial has error\n″);
exit(1);
}
sock=socket (AF-INET,SOCK-STREAM,0);
if (sock< 0)
{ perror(″can't create socket″);
exit (1);
}
comd- >sock=sock;/*服务器的socket号*/
bzero(&serve, sizeof(serve));
serve.sin-family=AF-INET;
serve.sin-addr.s-addr=INADDR-ANY;
serve.sin-port=htons (portnum);
if(bind(sock, (struct sockaddr
*)&serve, sizeof(serve))<0)
{ perror(″bind error″);
close(sock);
exit (1);
}
ioctl(sock,FIONBIO,&flags);/*置非阻塞方式*/
if (listen (sock, 5)< 0)
{ perror(″listen error″);
close(sock);
exit (1);
}
while (1)/*24小时实时监控*/
{
link-accept(sock);/*非阻塞连接*/
link-read();/*非阻塞轮询*/
} /* end while */
}/** end main **/
-
SCO UNIX网络编程技术在监控进程中的应用-sdccf-ChinaUnix博客
|
|
|
SCO UNIX网络编程技术在监控进程中的应用
(南京通信工程学院计算机室 李清 210016)
---- 现在许多通信网监控系统都采用分级监控系统,如图1所示。上级监控中心接收下级监控中心的数据,并对下级监控中心实施监视和控制。每级监控中心都配有监控软件,主要有服务器软件和客户机软件。服务器软件主要包括数据处理软件和监控进程,下面就SCO UNIX环境下监控进程的编制进行说明。
---- 在SCO UNIX环境下编制监控进程通常采用两种方法,并发服务器和重复服务器处理。
---- 所谓并发服务器就是监控进程在接收到客户的一个连接请求时,便产生一个进程专门与其进行通信并作相应处理,其程序流程如图2。在此期间,由于每产生一个子进程,其便拥有与父进程同样的资源,该方式下,来一个请求便产生一个子进程,当申请连接的请求超过一定数目,产生的子进程数达到一定量时,系统运行很慢,几乎不能正常工作,因此并发服务器适于与客户间的短暂通信,通信完毕后即断开连接,结束相应子进程。
---- 在一些大型通信网监控系统中,通常要求客户机全天候与服务器相连接以保证能实时进行监控,而且这些监控系统中要监视(或请求服务)的客户机都比较多,按照并发服务器方式处理不能保证进程的正常运行。我们在SCO UNIX环境下测试,当连接的 Int initsockid,newsockid;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
if(listen(initsockid,5< 0)
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*阻塞*/
if(newsockid< 0)
error(“accept error”);
if(fork()==0/*子进程*/
{
close(initsockid);
do(newsockid);/*处理请求*/
exit(0);
}
close(newsockid);/*父进程*/
}
图2 并发服务器
int initsockid, newsockid
int flags=1;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
ioctl(sockid,FIONBIO,&flags);/*非阻塞*/
if(listen(initsockid,5< 0);
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*非阻塞*/
if(newsockid< 0)
error(“accept error”);
ioctl(newsockid,FIONBIO,&flags);/*非阻塞*/
do(newsockid);/*处理请求*/
close(newsockid);
}
图3 轮询与非阻塞方式相结合的重复服务器
---- 客户机超过10个时,系统运行异常,甚至出现死机。为了解决这个问题,采用第二种方法,即重复服务器处理,并将轮询和非阻塞方式相结合,其程序流程如图3
---- 所谓重复服务器处理就是当服务器接收到客户机的连接请求时,并不产生专门子进程,而是直接进行处理,这里便存在以下两种特殊情况:
---- (1)客户机只请求连接,并不进行数据传输。
---- (2)客户机请求连接后,进行大量数据传输。
---- 这两种情况在实时监控系统中有一个共同点是一旦连接上,除非客户断开连接,否则连接不能断开。
---- 在第一种情况下,若采用阻塞方式,则服务器一直等待已连接的客户机发送数据,这样,一方面不能及时接收其它客户机的连接请求,进行数据传输,进行实时性监控;另一方面,服务器处于闲置状态,造成资源浪费。而采用非阻塞方式则避免了上述情况,在非阻塞方式下,当连接的客户机没有数据传输时,服务器便转去处理别的客户机的请求。
---- 在第二种情况下,若服务器一旦与客户机相连后便接收其传来的数据,那么当客户机传输的数据量大时,接收和处理数据将占据一定时间,其间其它客户机就只能等待,不能得到及时处理。采用轮询法则可解决客户机长时间等待问题。
---- 轮询法的关键就是数据分段处理,每次以一个确定单位接收和处理客户机发来的数据,此单位大小取决于具体要连接的客户机数及传输数据报文的长度。为了保证服务器和客户机一次连接传输的数据能在同一次连接过程中完成(事实上也就是通过分配的同一个socket号进行接收),增加了一个辅助表。该表有客户机的IP地址,每次连接分配的socket号,以及其它信息。服务器每次接收到客户机连接请求后,便为其分配一个socket号,将其填入到辅助表对应的表项中,当下次轮询到此客户机时,服务器根据客户机的IP地址从辅助表中取出其对应的socket号,并根据此socket号进行数据接收和发送。辅助表中分配给客户机的socket号一直保留至接收到该客户机新的连接请求止。
---- 以下是一个具体实例。 #include < sys/types.h >
#include < sys/socket.h >
#include < netinet/in.h >
#include < stdio.h >
#include < errno.h >
#include < sys/ioctl.h >
#define MAX-LINKS 20 /* 所监控的客户机数目 */
#define PORTNUM 2330/*端口号*/
struct com-buf/*辅助表*/
{ struct m-table
{ char jkip[13];
char tz[5];
int msgsock;
int key;
} m-table[MAX-LINKS];
int skdb,sock;
}*comd;
int link-accept(s)
/**非阻塞方式接收客户机的连接请求 **/
int s; /* server socket */
{ int i, msgsock, flags=1; /* flags=1 非阻塞 */
struct sockaddr-in monitor;/*客户机 IP*/
if((msgsock=accept(s, (struct sockaddr)&monitor,
&sizeof(monitor)))< 0)/*非阻塞接收*/
{ perror(″no connections are pending″);
return 0;
}
for(i=0;i< MAX-LINKS;i++)
{ if(strcmp(comd- >m-table[i].
jkip,inet-ntoa(monitor.sin-addr))==0)
{ if (comd- >m-table[i].key==1)
close(comd- >m-table[i].msgsock);
ioctl(msgsock, FIONBIO,&flags); /* 置非阻塞方式 */
comd- >m-table[i].msgsock=msgsock
comd- >m-table[i].key=1
strcpy(a22, comd- >m-table[i].tz);
break;
}
}
return 1;
close(s);
}
void link-read()
/*非阻塞轮询方式接收客户机传来的数据*/
{ int msgsock, status, i;
char work[250];
for(i=0;i< MAX-LINKS;i++)
/* 轮询已连接的客户机 */
{ if (comd- >m-table[i].key==0) continue;
/*无连接则进行下一次轮询*/
msgsock=comd->m-table[i].msgsock;
/*从辅助表中取分配的socket号*/
bzero(work, sizeof(work));
/*数据接收的单位长度为sizeof(work)*/
if((status=recv(msgsock, work,
sizeof(work),0))< =0) /*非阻塞接收数据*/
{ if (status==0) errno=EHOSTDOWN;
status=RWError(msgsock);
continue; /* scan next link */
}
process(work);/*数据处理程序*/
}/** end of for (i=0;i< MAX-LINKS;i++) **/
}/** end of read all links **/
main ()
{ int sock, flags=1;
/* flags=1 置非阻塞标志 */
struct sockaddr-in serve;
/** server internet addr***/
if (initial () ==0)/*初始化辅助表*/
{ printf(″initial has error\n″);
exit(1);
}
sock=socket (AF-INET,SOCK-STREAM,0);
if (sock< 0)
{ perror(″can't create socket″);
exit (1);
}
comd- >sock=sock;/*服务器的socket号*/
bzero(&serve, sizeof(serve));
serve.sin-family=AF-INET;
serve.sin-addr.s-addr=INADDR-ANY;
serve.sin-port=htons (portnum);
if(bind(sock, (struct sockaddr
*)&serve, sizeof(serve))<0)
{ perror(″bind error″);
close(sock);
exit (1);
}
ioctl(sock,FIONBIO,&flags);/*置非阻塞方式*/
if (listen (sock, 5)< 0)
{ perror(″listen error″);
close(sock);
exit (1);
}
while (1)/*24小时实时监控*/
{
link-accept(sock);/*非阻塞连接*/
link-read();/*非阻塞轮询*/
} /* end while */
}/** end main **/
-
SCO UNIX网络编程技术在监控进程中的应用-sdccf-ChinaUnix博客
|
|
|
SCO UNIX网络编程技术在监控进程中的应用
(南京通信工程学院计算机室 李清 210016)
---- 现在许多通信网监控系统都采用分级监控系统,如图1所示。上级监控中心接收下级监控中心的数据,并对下级监控中心实施监视和控制。每级监控中心都配有监控软件,主要有服务器软件和客户机软件。服务器软件主要包括数据处理软件和监控进程,下面就SCO UNIX环境下监控进程的编制进行说明。
---- 在SCO UNIX环境下编制监控进程通常采用两种方法,并发服务器和重复服务器处理。
---- 所谓并发服务器就是监控进程在接收到客户的一个连接请求时,便产生一个进程专门与其进行通信并作相应处理,其程序流程如图2。在此期间,由于每产生一个子进程,其便拥有与父进程同样的资源,该方式下,来一个请求便产生一个子进程,当申请连接的请求超过一定数目,产生的子进程数达到一定量时,系统运行很慢,几乎不能正常工作,因此并发服务器适于与客户间的短暂通信,通信完毕后即断开连接,结束相应子进程。
---- 在一些大型通信网监控系统中,通常要求客户机全天候与服务器相连接以保证能实时进行监控,而且这些监控系统中要监视(或请求服务)的客户机都比较多,按照并发服务器方式处理不能保证进程的正常运行。我们在SCO UNIX环境下测试,当连接的 Int initsockid,newsockid;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
if(listen(initsockid,5< 0)
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*阻塞*/
if(newsockid< 0)
error(“accept error”);
if(fork()==0/*子进程*/
{
close(initsockid);
do(newsockid);/*处理请求*/
exit(0);
}
close(newsockid);/*父进程*/
}
图2 并发服务器
int initsockid, newsockid
int flags=1;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
ioctl(sockid,FIONBIO,&flags);/*非阻塞*/
if(listen(initsockid,5< 0);
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*非阻塞*/
if(newsockid< 0)
error(“accept error”);
ioctl(newsockid,FIONBIO,&flags);/*非阻塞*/
do(newsockid);/*处理请求*/
close(newsockid);
}
图3 轮询与非阻塞方式相结合的重复服务器
---- 客户机超过10个时,系统运行异常,甚至出现死机。为了解决这个问题,采用第二种方法,即重复服务器处理,并将轮询和非阻塞方式相结合,其程序流程如图3
---- 所谓重复服务器处理就是当服务器接收到客户机的连接请求时,并不产生专门子进程,而是直接进行处理,这里便存在以下两种特殊情况:
---- (1)客户机只请求连接,并不进行数据传输。
---- (2)客户机请求连接后,进行大量数据传输。
---- 这两种情况在实时监控系统中有一个共同点是一旦连接上,除非客户断开连接,否则连接不能断开。
---- 在第一种情况下,若采用阻塞方式,则服务器一直等待已连接的客户机发送数据,这样,一方面不能及时接收其它客户机的连接请求,进行数据传输,进行实时性监控;另一方面,服务器处于闲置状态,造成资源浪费。而采用非阻塞方式则避免了上述情况,在非阻塞方式下,当连接的客户机没有数据传输时,服务器便转去处理别的客户机的请求。
---- 在第二种情况下,若服务器一旦与客户机相连后便接收其传来的数据,那么当客户机传输的数据量大时,接收和处理数据将占据一定时间,其间其它客户机就只能等待,不能得到及时处理。采用轮询法则可解决客户机长时间等待问题。
---- 轮询法的关键就是数据分段处理,每次以一个确定单位接收和处理客户机发来的数据,此单位大小取决于具体要连接的客户机数及传输数据报文的长度。为了保证服务器和客户机一次连接传输的数据能在同一次连接过程中完成(事实上也就是通过分配的同一个socket号进行接收),增加了一个辅助表。该表有客户机的IP地址,每次连接分配的socket号,以及其它信息。服务器每次接收到客户机连接请求后,便为其分配一个socket号,将其填入到辅助表对应的表项中,当下次轮询到此客户机时,服务器根据客户机的IP地址从辅助表中取出其对应的socket号,并根据此socket号进行数据接收和发送。辅助表中分配给客户机的socket号一直保留至接收到该客户机新的连接请求止。
---- 以下是一个具体实例。 #include < sys/types.h >
#include < sys/socket.h >
#include < netinet/in.h >
#include < stdio.h >
#include < errno.h >
#include < sys/ioctl.h >
#define MAX-LINKS 20 /* 所监控的客户机数目 */
#define PORTNUM 2330/*端口号*/
struct com-buf/*辅助表*/
{ struct m-table
{ char jkip[13];
char tz[5];
int msgsock;
int key;
} m-table[MAX-LINKS];
int skdb,sock;
}*comd;
int link-accept(s)
/**非阻塞方式接收客户机的连接请求 **/
int s; /* server socket */
{ int i, msgsock, flags=1; /* flags=1 非阻塞 */
struct sockaddr-in monitor;/*客户机 IP*/
if((msgsock=accept(s, (struct sockaddr)&monitor,
&sizeof(monitor)))< 0)/*非阻塞接收*/
{ perror(″no connections are pending″);
return 0;
}
for(i=0;i< MAX-LINKS;i++)
{ if(strcmp(comd- >m-table[i].
jkip,inet-ntoa(monitor.sin-addr))==0)
{ if (comd- >m-table[i].key==1)
close(comd- >m-table[i].msgsock);
ioctl(msgsock, FIONBIO,&flags); /* 置非阻塞方式 */
comd- >m-table[i].msgsock=msgsock
comd- >m-table[i].key=1
strcpy(a22, comd- >m-table[i].tz);
break;
}
}
return 1;
close(s);
}
void link-read()
/*非阻塞轮询方式接收客户机传来的数据*/
{ int msgsock, status, i;
char work[250];
for(i=0;i< MAX-LINKS;i++)
/* 轮询已连接的客户机 */
{ if (comd- >m-table[i].key==0) continue;
/*无连接则进行下一次轮询*/
msgsock=comd->m-table[i].msgsock;
/*从辅助表中取分配的socket号*/
bzero(work, sizeof(work));
/*数据接收的单位长度为sizeof(work)*/
if((status=recv(msgsock, work,
sizeof(work),0))< =0) /*非阻塞接收数据*/
{ if (status==0) errno=EHOSTDOWN;
status=RWError(msgsock);
continue; /* scan next link */
}
process(work);/*数据处理程序*/
}/** end of for (i=0;i< MAX-LINKS;i++) **/
}/** end of read all links **/
main ()
{ int sock, flags=1;
/* flags=1 置非阻塞标志 */
struct sockaddr-in serve;
/** server internet addr***/
if (initial () ==0)/*初始化辅助表*/
{ printf(″initial has error\n″);
exit(1);
}
sock=socket (AF-INET,SOCK-STREAM,0);
if (sock< 0)
{ perror(″can't create socket″);
exit (1);
}
comd- >sock=sock;/*服务器的socket号*/
bzero(&serve, sizeof(serve));
serve.sin-family=AF-INET;
serve.sin-addr.s-addr=INADDR-ANY;
serve.sin-port=htons (portnum);
if(bind(sock, (struct sockaddr
*)&serve, sizeof(serve))<0)
{ perror(″bind error″);
close(sock);
exit (1);
}
ioctl(sock,FIONBIO,&flags);/*置非阻塞方式*/
if (listen (sock, 5)< 0)
{ perror(″listen error″);
close(sock);
exit (1);
}
while (1)/*24小时实时监控*/
{
link-accept(sock);/*非阻塞连接*/
link-read();/*非阻塞轮询*/
} /* end while */
}/** end main **/
-
SCO UNIX网络编程技术在监控进程中的应用-sdccf-ChinaUnix博客
|
|
|
SCO UNIX网络编程技术在监控进程中的应用
(南京通信工程学院计算机室 李清 210016)
---- 现在许多通信网监控系统都采用分级监控系统,如图1所示。上级监控中心接收下级监控中心的数据,并对下级监控中心实施监视和控制。每级监控中心都配有监控软件,主要有服务器软件和客户机软件。服务器软件主要包括数据处理软件和监控进程,下面就SCO UNIX环境下监控进程的编制进行说明。
---- 在SCO UNIX环境下编制监控进程通常采用两种方法,并发服务器和重复服务器处理。
---- 所谓并发服务器就是监控进程在接收到客户的一个连接请求时,便产生一个进程专门与其进行通信并作相应处理,其程序流程如图2。在此期间,由于每产生一个子进程,其便拥有与父进程同样的资源,该方式下,来一个请求便产生一个子进程,当申请连接的请求超过一定数目,产生的子进程数达到一定量时,系统运行很慢,几乎不能正常工作,因此并发服务器适于与客户间的短暂通信,通信完毕后即断开连接,结束相应子进程。
---- 在一些大型通信网监控系统中,通常要求客户机全天候与服务器相连接以保证能实时进行监控,而且这些监控系统中要监视(或请求服务)的客户机都比较多,按照并发服务器方式处理不能保证进程的正常运行。我们在SCO UNIX环境下测试,当连接的 Int initsockid,newsockid;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
if(listen(initsockid,5< 0)
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*阻塞*/
if(newsockid< 0)
error(“accept error”);
if(fork()==0/*子进程*/
{
close(initsockid);
do(newsockid);/*处理请求*/
exit(0);
}
close(newsockid);/*父进程*/
}
图2 并发服务器
int initsockid, newsockid
int flags=1;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
ioctl(sockid,FIONBIO,&flags);/*非阻塞*/
if(listen(initsockid,5< 0);
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*非阻塞*/
if(newsockid< 0)
error(“accept error”);
ioctl(newsockid,FIONBIO,&flags);/*非阻塞*/
do(newsockid);/*处理请求*/
close(newsockid);
}
图3 轮询与非阻塞方式相结合的重复服务器
---- 客户机超过10个时,系统运行异常,甚至出现死机。为了解决这个问题,采用第二种方法,即重复服务器处理,并将轮询和非阻塞方式相结合,其程序流程如图3
---- 所谓重复服务器处理就是当服务器接收到客户机的连接请求时,并不产生专门子进程,而是直接进行处理,这里便存在以下两种特殊情况:
---- (1)客户机只请求连接,并不进行数据传输。
---- (2)客户机请求连接后,进行大量数据传输。
---- 这两种情况在实时监控系统中有一个共同点是一旦连接上,除非客户断开连接,否则连接不能断开。
---- 在第一种情况下,若采用阻塞方式,则服务器一直等待已连接的客户机发送数据,这样,一方面不能及时接收其它客户机的连接请求,进行数据传输,进行实时性监控;另一方面,服务器处于闲置状态,造成资源浪费。而采用非阻塞方式则避免了上述情况,在非阻塞方式下,当连接的客户机没有数据传输时,服务器便转去处理别的客户机的请求。
---- 在第二种情况下,若服务器一旦与客户机相连后便接收其传来的数据,那么当客户机传输的数据量大时,接收和处理数据将占据一定时间,其间其它客户机就只能等待,不能得到及时处理。采用轮询法则可解决客户机长时间等待问题。
---- 轮询法的关键就是数据分段处理,每次以一个确定单位接收和处理客户机发来的数据,此单位大小取决于具体要连接的客户机数及传输数据报文的长度。为了保证服务器和客户机一次连接传输的数据能在同一次连接过程中完成(事实上也就是通过分配的同一个socket号进行接收),增加了一个辅助表。该表有客户机的IP地址,每次连接分配的socket号,以及其它信息。服务器每次接收到客户机连接请求后,便为其分配一个socket号,将其填入到辅助表对应的表项中,当下次轮询到此客户机时,服务器根据客户机的IP地址从辅助表中取出其对应的socket号,并根据此socket号进行数据接收和发送。辅助表中分配给客户机的socket号一直保留至接收到该客户机新的连接请求止。
---- 以下是一个具体实例。 #include < sys/types.h >
#include < sys/socket.h >
#include < netinet/in.h >
#include < stdio.h >
#include < errno.h >
#include < sys/ioctl.h >
#define MAX-LINKS 20 /* 所监控的客户机数目 */
#define PORTNUM 2330/*端口号*/
struct com-buf/*辅助表*/
{ struct m-table
{ char jkip[13];
char tz[5];
int msgsock;
int key;
} m-table[MAX-LINKS];
int skdb,sock;
}*comd;
int link-accept(s)
/**非阻塞方式接收客户机的连接请求 **/
int s; /* server socket */
{ int i, msgsock, flags=1; /* flags=1 非阻塞 */
struct sockaddr-in monitor;/*客户机 IP*/
if((msgsock=accept(s, (struct sockaddr)&monitor,
&sizeof(monitor)))< 0)/*非阻塞接收*/
{ perror(″no connections are pending″);
return 0;
}
for(i=0;i< MAX-LINKS;i++)
{ if(strcmp(comd- >m-table[i].
jkip,inet-ntoa(monitor.sin-addr))==0)
{ if (comd- >m-table[i].key==1)
close(comd- >m-table[i].msgsock);
ioctl(msgsock, FIONBIO,&flags); /* 置非阻塞方式 */
comd- >m-table[i].msgsock=msgsock
comd- >m-table[i].key=1
strcpy(a22, comd- >m-table[i].tz);
break;
}
}
return 1;
close(s);
}
void link-read()
/*非阻塞轮询方式接收客户机传来的数据*/
{ int msgsock, status, i;
char work[250];
for(i=0;i< MAX-LINKS;i++)
/* 轮询已连接的客户机 */
{ if (comd- >m-table[i].key==0) continue;
/*无连接则进行下一次轮询*/
msgsock=comd->m-table[i].msgsock;
/*从辅助表中取分配的socket号*/
bzero(work, sizeof(work));
/*数据接收的单位长度为sizeof(work)*/
if((status=recv(msgsock, work,
sizeof(work),0))< =0) /*非阻塞接收数据*/
{ if (status==0) errno=EHOSTDOWN;
status=RWError(msgsock);
continue; /* scan next link */
}
process(work);/*数据处理程序*/
}/** end of for (i=0;i< MAX-LINKS;i++) **/
}/** end of read all links **/
main ()
{ int sock, flags=1;
/* flags=1 置非阻塞标志 */
struct sockaddr-in serve;
/** server internet addr***/
if (initial () ==0)/*初始化辅助表*/
{ printf(″initial has error\n″);
exit(1);
}
sock=socket (AF-INET,SOCK-STREAM,0);
if (sock< 0)
{ perror(″can't create socket″);
exit (1);
}
comd- >sock=sock;/*服务器的socket号*/
bzero(&serve, sizeof(serve));
serve.sin-family=AF-INET;
serve.sin-addr.s-addr=INADDR-ANY;
serve.sin-port=htons (portnum);
if(bind(sock, (struct sockaddr
*)&serve, sizeof(serve))<0)
{ perror(″bind error″);
close(sock);
exit (1);
}
ioctl(sock,FIONBIO,&flags);/*置非阻塞方式*/
if (listen (sock, 5)< 0)
{ perror(″listen error″);
close(sock);
exit (1);
}
while (1)/*24小时实时监控*/
{
link-accept(sock);/*非阻塞连接*/
link-read();/*非阻塞轮询*/
} /* end while */
}/** end main **/
-
SCO UNIX网络编程技术在监控进程中的应用-sdccf-ChinaUnix博客
|
|
|
SCO UNIX网络编程技术在监控进程中的应用
(南京通信工程学院计算机室 李清 210016)
---- 现在许多通信网监控系统都采用分级监控系统,如图1所示。上级监控中心接收下级监控中心的数据,并对下级监控中心实施监视和控制。每级监控中心都配有监控软件,主要有服务器软件和客户机软件。服务器软件主要包括数据处理软件和监控进程,下面就SCO UNIX环境下监控进程的编制进行说明。
---- 在SCO UNIX环境下编制监控进程通常采用两种方法,并发服务器和重复服务器处理。
---- 所谓并发服务器就是监控进程在接收到客户的一个连接请求时,便产生一个进程专门与其进行通信并作相应处理,其程序流程如图2。在此期间,由于每产生一个子进程,其便拥有与父进程同样的资源,该方式下,来一个请求便产生一个子进程,当申请连接的请求超过一定数目,产生的子进程数达到一定量时,系统运行很慢,几乎不能正常工作,因此并发服务器适于与客户间的短暂通信,通信完毕后即断开连接,结束相应子进程。
---- 在一些大型通信网监控系统中,通常要求客户机全天候与服务器相连接以保证能实时进行监控,而且这些监控系统中要监视(或请求服务)的客户机都比较多,按照并发服务器方式处理不能保证进程的正常运行。我们在SCO UNIX环境下测试,当连接的 Int initsockid,newsockid;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
if(listen(initsockid,5< 0)
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*阻塞*/
if(newsockid< 0)
error(“accept error”);
if(fork()==0/*子进程*/
{
close(initsockid);
do(newsockid);/*处理请求*/
exit(0);
}
close(newsockid);/*父进程*/
}
图2 并发服务器
int initsockid, newsockid
int flags=1;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
ioctl(sockid,FIONBIO,&flags);/*非阻塞*/
if(listen(initsockid,5< 0);
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*非阻塞*/
if(newsockid< 0)
error(“accept error”);
ioctl(newsockid,FIONBIO,&flags);/*非阻塞*/
do(newsockid);/*处理请求*/
close(newsockid);
}
图3 轮询与非阻塞方式相结合的重复服务器
---- 客户机超过10个时,系统运行异常,甚至出现死机。为了解决这个问题,采用第二种方法,即重复服务器处理,并将轮询和非阻塞方式相结合,其程序流程如图3
---- 所谓重复服务器处理就是当服务器接收到客户机的连接请求时,并不产生专门子进程,而是直接进行处理,这里便存在以下两种特殊情况:
---- (1)客户机只请求连接,并不进行数据传输。
---- (2)客户机请求连接后,进行大量数据传输。
---- 这两种情况在实时监控系统中有一个共同点是一旦连接上,除非客户断开连接,否则连接不能断开。
---- 在第一种情况下,若采用阻塞方式,则服务器一直等待已连接的客户机发送数据,这样,一方面不能及时接收其它客户机的连接请求,进行数据传输,进行实时性监控;另一方面,服务器处于闲置状态,造成资源浪费。而采用非阻塞方式则避免了上述情况,在非阻塞方式下,当连接的客户机没有数据传输时,服务器便转去处理别的客户机的请求。
---- 在第二种情况下,若服务器一旦与客户机相连后便接收其传来的数据,那么当客户机传输的数据量大时,接收和处理数据将占据一定时间,其间其它客户机就只能等待,不能得到及时处理。采用轮询法则可解决客户机长时间等待问题。
---- 轮询法的关键就是数据分段处理,每次以一个确定单位接收和处理客户机发来的数据,此单位大小取决于具体要连接的客户机数及传输数据报文的长度。为了保证服务器和客户机一次连接传输的数据能在同一次连接过程中完成(事实上也就是通过分配的同一个socket号进行接收),增加了一个辅助表。该表有客户机的IP地址,每次连接分配的socket号,以及其它信息。服务器每次接收到客户机连接请求后,便为其分配一个socket号,将其填入到辅助表对应的表项中,当下次轮询到此客户机时,服务器根据客户机的IP地址从辅助表中取出其对应的socket号,并根据此socket号进行数据接收和发送。辅助表中分配给客户机的socket号一直保留至接收到该客户机新的连接请求止。
---- 以下是一个具体实例。 #include < sys/types.h >
#include < sys/socket.h >
#include < netinet/in.h >
#include < stdio.h >
#include < errno.h >
#include < sys/ioctl.h >
#define MAX-LINKS 20 /* 所监控的客户机数目 */
#define PORTNUM 2330/*端口号*/
struct com-buf/*辅助表*/
{ struct m-table
{ char jkip[13];
char tz[5];
int msgsock;
int key;
} m-table[MAX-LINKS];
int skdb,sock;
}*comd;
int link-accept(s)
/**非阻塞方式接收客户机的连接请求 **/
int s; /* server socket */
{ int i, msgsock, flags=1; /* flags=1 非阻塞 */
struct sockaddr-in monitor;/*客户机 IP*/
if((msgsock=accept(s, (struct sockaddr)&monitor,
&sizeof(monitor)))< 0)/*非阻塞接收*/
{ perror(″no connections are pending″);
return 0;
}
for(i=0;i< MAX-LINKS;i++)
{ if(strcmp(comd- >m-table[i].
jkip,inet-ntoa(monitor.sin-addr))==0)
{ if (comd- >m-table[i].key==1)
close(comd- >m-table[i].msgsock);
ioctl(msgsock, FIONBIO,&flags); /* 置非阻塞方式 */
comd- >m-table[i].msgsock=msgsock
comd- >m-table[i].key=1
strcpy(a22, comd- >m-table[i].tz);
break;
}
}
return 1;
close(s);
}
void link-read()
/*非阻塞轮询方式接收客户机传来的数据*/
{ int msgsock, status, i;
char work[250];
for(i=0;i< MAX-LINKS;i++)
/* 轮询已连接的客户机 */
{ if (comd- >m-table[i].key==0) continue;
/*无连接则进行下一次轮询*/
msgsock=comd->m-table[i].msgsock;
/*从辅助表中取分配的socket号*/
bzero(work, sizeof(work));
/*数据接收的单位长度为sizeof(work)*/
if((status=recv(msgsock, work,
sizeof(work),0))< =0) /*非阻塞接收数据*/
{ if (status==0) errno=EHOSTDOWN;
status=RWError(msgsock);
continue; /* scan next link */
}
process(work);/*数据处理程序*/
}/** end of for (i=0;i< MAX-LINKS;i++) **/
}/** end of read all links **/
main ()
{ int sock, flags=1;
/* flags=1 置非阻塞标志 */
struct sockaddr-in serve;
/** server internet addr***/
if (initial () ==0)/*初始化辅助表*/
{ printf(″initial has error\n″);
exit(1);
}
sock=socket (AF-INET,SOCK-STREAM,0);
if (sock< 0)
{ perror(″can't create socket″);
exit (1);
}
comd- >sock=sock;/*服务器的socket号*/
bzero(&serve, sizeof(serve));
serve.sin-family=AF-INET;
serve.sin-addr.s-addr=INADDR-ANY;
serve.sin-port=htons (portnum);
if(bind(sock, (struct sockaddr
*)&serve, sizeof(serve))<0)
{ perror(″bind error″);
close(sock);
exit (1);
}
ioctl(sock,FIONBIO,&flags);/*置非阻塞方式*/
if (listen (sock, 5)< 0)
{ perror(″listen error″);
close(sock);
exit (1);
}
while (1)/*24小时实时监控*/
{
link-accept(sock);/*非阻塞连接*/
link-read();/*非阻塞轮询*/
} /* end while */
}/** end main **/
-
SCO UNIX网络编程技术在监控进程中的应用-sdccf-ChinaUnix博客
|
|
|
SCO UNIX网络编程技术在监控进程中的应用
(南京通信工程学院计算机室 李清 210016)
---- 现在许多通信网监控系统都采用分级监控系统,如图1所示。上级监控中心接收下级监控中心的数据,并对下级监控中心实施监视和控制。每级监控中心都配有监控软件,主要有服务器软件和客户机软件。服务器软件主要包括数据处理软件和监控进程,下面就SCO UNIX环境下监控进程的编制进行说明。
---- 在SCO UNIX环境下编制监控进程通常采用两种方法,并发服务器和重复服务器处理。
---- 所谓并发服务器就是监控进程在接收到客户的一个连接请求时,便产生一个进程专门与其进行通信并作相应处理,其程序流程如图2。在此期间,由于每产生一个子进程,其便拥有与父进程同样的资源,该方式下,来一个请求便产生一个子进程,当申请连接的请求超过一定数目,产生的子进程数达到一定量时,系统运行很慢,几乎不能正常工作,因此并发服务器适于与客户间的短暂通信,通信完毕后即断开连接,结束相应子进程。
---- 在一些大型通信网监控系统中,通常要求客户机全天候与服务器相连接以保证能实时进行监控,而且这些监控系统中要监视(或请求服务)的客户机都比较多,按照并发服务器方式处理不能保证进程的正常运行。我们在SCO UNIX环境下测试,当连接的 Int initsockid,newsockid;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
if(listen(initsockid,5< 0)
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*阻塞*/
if(newsockid< 0)
error(“accept error”);
if(fork()==0/*子进程*/
{
close(initsockid);
do(newsockid);/*处理请求*/
exit(0);
}
close(newsockid);/*父进程*/
}
图2 并发服务器
int initsockid, newsockid
int flags=1;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
ioctl(sockid,FIONBIO,&flags);/*非阻塞*/
if(listen(initsockid,5< 0);
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*非阻塞*/
if(newsockid< 0)
error(“accept error”);
ioctl(newsockid,FIONBIO,&flags);/*非阻塞*/
do(newsockid);/*处理请求*/
close(newsockid);
}
图3 轮询与非阻塞方式相结合的重复服务器
---- 客户机超过10个时,系统运行异常,甚至出现死机。为了解决这个问题,采用第二种方法,即重复服务器处理,并将轮询和非阻塞方式相结合,其程序流程如图3
---- 所谓重复服务器处理就是当服务器接收到客户机的连接请求时,并不产生专门子进程,而是直接进行处理,这里便存在以下两种特殊情况:
---- (1)客户机只请求连接,并不进行数据传输。
---- (2)客户机请求连接后,进行大量数据传输。
---- 这两种情况在实时监控系统中有一个共同点是一旦连接上,除非客户断开连接,否则连接不能断开。
---- 在第一种情况下,若采用阻塞方式,则服务器一直等待已连接的客户机发送数据,这样,一方面不能及时接收其它客户机的连接请求,进行数据传输,进行实时性监控;另一方面,服务器处于闲置状态,造成资源浪费。而采用非阻塞方式则避免了上述情况,在非阻塞方式下,当连接的客户机没有数据传输时,服务器便转去处理别的客户机的请求。
---- 在第二种情况下,若服务器一旦与客户机相连后便接收其传来的数据,那么当客户机传输的数据量大时,接收和处理数据将占据一定时间,其间其它客户机就只能等待,不能得到及时处理。采用轮询法则可解决客户机长时间等待问题。
---- 轮询法的关键就是数据分段处理,每次以一个确定单位接收和处理客户机发来的数据,此单位大小取决于具体要连接的客户机数及传输数据报文的长度。为了保证服务器和客户机一次连接传输的数据能在同一次连接过程中完成(事实上也就是通过分配的同一个socket号进行接收),增加了一个辅助表。该表有客户机的IP地址,每次连接分配的socket号,以及其它信息。服务器每次接收到客户机连接请求后,便为其分配一个socket号,将其填入到辅助表对应的表项中,当下次轮询到此客户机时,服务器根据客户机的IP地址从辅助表中取出其对应的socket号,并根据此socket号进行数据接收和发送。辅助表中分配给客户机的socket号一直保留至接收到该客户机新的连接请求止。
---- 以下是一个具体实例。 #include < sys/types.h >
#include < sys/socket.h >
#include < netinet/in.h >
#include < stdio.h >
#include < errno.h >
#include < sys/ioctl.h >
#define MAX-LINKS 20 /* 所监控的客户机数目 */
#define PORTNUM 2330/*端口号*/
struct com-buf/*辅助表*/
{ struct m-table
{ char jkip[13];
char tz[5];
int msgsock;
int key;
} m-table[MAX-LINKS];
int skdb,sock;
}*comd;
int link-accept(s)
/**非阻塞方式接收客户机的连接请求 **/
int s; /* server socket */
{ int i, msgsock, flags=1; /* flags=1 非阻塞 */
struct sockaddr-in monitor;/*客户机 IP*/
if((msgsock=accept(s, (struct sockaddr)&monitor,
&sizeof(monitor)))< 0)/*非阻塞接收*/
{ perror(″no connections are pending″);
return 0;
}
for(i=0;i< MAX-LINKS;i++)
{ if(strcmp(comd- >m-table[i].
jkip,inet-ntoa(monitor.sin-addr))==0)
{ if (comd- >m-table[i].key==1)
close(comd- >m-table[i].msgsock);
ioctl(msgsock, FIONBIO,&flags); /* 置非阻塞方式 */
comd- >m-table[i].msgsock=msgsock
comd- >m-table[i].key=1
strcpy(a22, comd- >m-table[i].tz);
break;
}
}
return 1;
close(s);
}
void link-read()
/*非阻塞轮询方式接收客户机传来的数据*/
{ int msgsock, status, i;
char work[250];
for(i=0;i< MAX-LINKS;i++)
/* 轮询已连接的客户机 */
{ if (comd- >m-table[i].key==0) continue;
/*无连接则进行下一次轮询*/
msgsock=comd->m-table[i].msgsock;
/*从辅助表中取分配的socket号*/
bzero(work, sizeof(work));
/*数据接收的单位长度为sizeof(work)*/
if((status=recv(msgsock, work,
sizeof(work),0))< =0) /*非阻塞接收数据*/
{ if (status==0) errno=EHOSTDOWN;
status=RWError(msgsock);
continue; /* scan next link */
}
process(work);/*数据处理程序*/
}/** end of for (i=0;i< MAX-LINKS;i++) **/
}/** end of read all links **/
main ()
{ int sock, flags=1;
/* flags=1 置非阻塞标志 */
struct sockaddr-in serve;
/** server internet addr***/
if (initial () ==0)/*初始化辅助表*/
{ printf(″initial has error\n″);
exit(1);
}
sock=socket (AF-INET,SOCK-STREAM,0);
if (sock< 0)
{ perror(″can't create socket″);
exit (1);
}
comd- >sock=sock;/*服务器的socket号*/
bzero(&serve, sizeof(serve));
serve.sin-family=AF-INET;
serve.sin-addr.s-addr=INADDR-ANY;
serve.sin-port=htons (portnum);
if(bind(sock, (struct sockaddr
*)&serve, sizeof(serve))<0)
{ perror(″bind error″);
close(sock);
exit (1);
}
ioctl(sock,FIONBIO,&flags);/*置非阻塞方式*/
if (listen (sock, 5)< 0)
{ perror(″listen error″);
close(sock);
exit (1);
}
while (1)/*24小时实时监控*/
{
link-accept(sock);/*非阻塞连接*/
link-read();/*非阻塞轮询*/
} /* end while */
}/** end main **/
-
SCO UNIX网络编程技术在监控进程中的应用-sdccf-ChinaUnix博客
|
|
|
SCO UNIX网络编程技术在监控进程中的应用
(南京通信工程学院计算机室 李清 210016)
---- 现在许多通信网监控系统都采用分级监控系统,如图1所示。上级监控中心接收下级监控中心的数据,并对下级监控中心实施监视和控制。每级监控中心都配有监控软件,主要有服务器软件和客户机软件。服务器软件主要包括数据处理软件和监控进程,下面就SCO UNIX环境下监控进程的编制进行说明。
---- 在SCO UNIX环境下编制监控进程通常采用两种方法,并发服务器和重复服务器处理。
---- 所谓并发服务器就是监控进程在接收到客户的一个连接请求时,便产生一个进程专门与其进行通信并作相应处理,其程序流程如图2。在此期间,由于每产生一个子进程,其便拥有与父进程同样的资源,该方式下,来一个请求便产生一个子进程,当申请连接的请求超过一定数目,产生的子进程数达到一定量时,系统运行很慢,几乎不能正常工作,因此并发服务器适于与客户间的短暂通信,通信完毕后即断开连接,结束相应子进程。
---- 在一些大型通信网监控系统中,通常要求客户机全天候与服务器相连接以保证能实时进行监控,而且这些监控系统中要监视(或请求服务)的客户机都比较多,按照并发服务器方式处理不能保证进程的正常运行。我们在SCO UNIX环境下测试,当连接的 Int initsockid,newsockid;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
if(listen(initsockid,5< 0)
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*阻塞*/
if(newsockid< 0)
error(“accept error”);
if(fork()==0/*子进程*/
{
close(initsockid);
do(newsockid);/*处理请求*/
exit(0);
}
close(newsockid);/*父进程*/
}
图2 并发服务器
int initsockid, newsockid
int flags=1;
if(initsockid=socket(…))< 0)
error(“can't create socket”);
if(bind(initsockid,…)< 0)
error(“bind error”);
ioctl(sockid,FIONBIO,&flags);/*非阻塞*/
if(listen(initsockid,5< 0);
error(“listen error”) ;
for(;;)
{ newsockis=accept(initsockid,…)/*非阻塞*/
if(newsockid< 0)
error(“accept error”);
ioctl(newsockid,FIONBIO,&flags);/*非阻塞*/
do(newsockid);/*处理请求*/
close(newsockid);
}
图3 轮询与非阻塞方式相结合的重复服务器
---- 客户机超过10个时,系统运行异常,甚至出现死机。为了解决这个问题,采用第二种方法,即重复服务器处理,并将轮询和非阻塞方式相结合,其程序流程如图3
---- 所谓重复服务器处理就是当服务器接收到客户机的连接请求时,并不产生专门子进程,而是直接进行处理,这里便存在以下两种特殊情况:
---- (1)客户机只请求连接,并不进行数据传输。
---- (2)客户机请求连接后,进行大量数据传输。
---- 这两种情况在实时监控系统中有一个共同点是一旦连接上,除非客户断开连接,否则连接不能断开。
---- 在第一种情况下,若采用阻塞方式,则服务器一直等待已连接的客户机发送数据,这样,一方面不能及时接收其它客户机的连接请求,进行数据传输,进行实时性监控;另一方面,服务器处于闲置状态,造成资源浪费。而采用非阻塞方式则避免了上述情况,在非阻塞方式下,当连接的客户机没有数据传输时,服务器便转去处理别的客户机的请求。
---- 在第二种情况下,若服务器一旦与客户机相连后便接收其传来的数据,那么当客户机传输的数据量大时,接收和处理数据将占据一定时间,其间其它客户机就只能等待,不能得到及时处理。采用轮询法则可解决客户机长时间等待问题。
---- 轮询法的关键就是数据分段处理,每次以一个确定单位接收和处理客户机发来的数据,此单位大小取决于具体要连接的客户机数及传输数据报文的长度。为了保证服务器和客户机一次连接传输的数据能在同一次连接过程中完成(事实上也就是通过分配的同一个socket号进行接收),增加了一个辅助表。该表有客户机的IP地址,每次连接分配的socket号,以及其它信息。服务器每次接收到客户机连接请求后,便为其分配一个socket号,将其填入到辅助表对应的表项中,当下次轮询到此客户机时,服务器根据客户机的IP地址从辅助表中取出其对应的socket号,并根据此socket号进行数据接收和发送。辅助表中分配给客户机的socket号一直保留至接收到该客户机新的连接请求止。
---- 以下是一个具体实例。 #include < sys/types.h >
#include < sys/socket.h >
#include < netinet/in.h >
#include < stdio.h >
#include < errno.h >
#include < sys/ioctl.h >
#define MAX-LINKS 20 /* 所监控的客户机数目 */
#define PORTNUM 2330/*端口号*/
struct com-buf/*辅助表*/
{ struct m-table
{ char jkip[13];
char tz[5];
int msgsock;
int key;
} m-table[MAX-LINKS];
int skdb,sock;
}*comd;
int link-accept(s)
/**非阻塞方式接收客户机的连接请求 **/
int s; /* server socket */
{ int i, msgsock, flags=1; /* flags=1 非阻塞 */
struct sockaddr-in monitor;/*客户机 IP*/
if((msgsock=accept(s, (struct sockaddr)&monitor,
&sizeof(monitor)))< 0)/*非阻塞接收*/
{ perror(″no connections are pending″);
return 0;
}
for(i=0;i< MAX-LINKS;i++)
{ if(strcmp(comd- >m-table[i].
jkip,inet-ntoa(monitor.sin-addr))==0)
{ if (comd- >m-table[i].key==1)
close(comd- >m-table[i].msgsock);
ioctl(msgsock, FIONBIO,&flags); /* 置非阻塞方式 */
comd- >m-table[i].msgsock=msgsock
comd- >m-table[i].key=1
strcpy(a22, comd- >m-table[i].tz);
break;
}
}
return 1;
close(s);
}
void link-read()
/*非阻塞轮询方式接收客户机传来的数据*/
{ int msgsock, status, i;
char work[250];
for(i=0;i< MAX-LINKS;i++)
/* 轮询已连接的客户机 */
{ if (comd- >m-table[i].key==0) continue;
/*无连接则进行下一次轮询*/
msgsock=comd->m-table[i].msgsock;
/*从辅助表中取分配的socket号*/
bzero(work, sizeof(work));
/*数据接收的单位长度为sizeof(work)*/
if((status=recv(msgsock, work,
sizeof(work),0))< =0) /*非阻塞接收数据*/
{ if (status==0) errno=EHOSTDOWN;
status=RWError(msgsock);
continue; /* scan next link */
}
process(work);/*数据处理程序*/
}/** end of for (i=0;i< MAX-LINKS;i++) **/
}/** end of read all links **/
main ()
{ int sock, flags=1;
/* flags=1 置非阻塞标志 */
struct sockaddr-in serve;
/** server internet addr***/
if (initial () ==0)/*初始化辅助表*/
{ printf(″initial has error\n″);
exit(1);
}
sock=socket (AF-INET,SOCK-STREAM,0);
if (sock< 0)
{ perror(″can't create socket″);
exit (1);
}
comd- >sock=sock;/*服务器的socket号*/
bzero(&serve, sizeof(serve));
serve.sin-family=AF-INET;
serve.sin-addr.s-addr=INADDR-ANY;
serve.sin-port=htons (portnum);
if(bind(sock, (struct sockaddr
*)&serve, sizeof(serve))<0)
{ perror(″bind error″);
close(sock);
exit (1);
}
ioctl(sock,FIONBIO,&flags);/*置非阻塞方式*/
if (listen (sock, 5)< 0)
{ perror(″listen error″);
close(sock);
exit (1);
}
while (1)/*24小时实时监控*/
{
link-accept(sock);/*非阻塞连接*/
link-read();/*非阻塞轮询*/
} /* end while */
}/** end main **/
-
SCO UNIX网络编程技术在监控进程中的应用-sdccf-ChinaUnix博客
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |