BBS水木清华站∶精华区

 
在 UNIX 系统发展应用程式入门 (二)                王志祥 
 
 
 
 
取得 User 资料的 pitch 函数: 
        上其的 FindMan 的 Initial 部份提到两个 User Define 的函数, 
一个是 catch, 另一个即是 pitch. Initial 部份 fork 的二十个程序都呼叫 
 pitch 函数向二十台工作站收集 User login 的资料并筛选出使用者所需的 
资料, 先整理出来的程序便先向主程序要求传送资料, 传送以 Socket 完成. 
有关 Socket 的部份以後再谈. 以下是 pitch 函数的部份程式: 
 
pitch(host) 
    char *host; 

     int bufsize; 
     int ps, j, k, l; 
     char buffer[BUFSIZE]; 
     int count; 
     struct  utmpidlearr     up; 
     int     tmp, gcount, gidx[25]; 
     char    gname[25][80]; 
     char    line[25][9]; 
     char    name[25][9]; 
     char    hhost[25][17]; 
     long    time[25]; 
     unsigned idle[25]; 
     char temp[80]; 
 
     up.uia_arr=(struct utmpidle **) malloc(25*sizeof(struct utmpidle *)); 
 
        :       :               : 
        :       :               : 
        /* 此处省略要求 Connect 的 Socket 之 Initial 部份. */ 
        :       :               : 
        :       :               : 
 
 
        strcpy(buffer,host); 
        k=strlen(host); 
        strcpy(&buffer[k],":\n"); 
        k+=2; 
        if ( rusers(host, &up) == 0 ) { 
           count = up.uia_cnt; 
           buffer[k++] = (char) count; 
           for ( j=0; j<count; j++) { 
             strncpy(line[j],up.uia_arr[j]->ui_utmp.ut_line,8); 
             line[j][8]='\0'; 
             strncpy(name[j],up.uia_arr[j]->ui_utmp.ut_name,8); 
             name[j][8]='\0'; 
             strncpy(hhost[j],up.uia_arr[j]->ui_utmp.ut_host,16); 
             hhost[j][16]='\0'; 
             time[j]=up.uia_arr[j]->ui_utmp.ut_time; 
             idle[j]=up.uia_arr[j]->ui_idle; 
            } 
               if (count != 0) { 
                 gcount=check(count,name,gname,gidx); 
                 buffer[k++] = (char) gcount; 
                 if (gcount !=0) 
                   for (j=0; j<gcount;) { 
                     strcpy(&buffer[k],gname[j]); 
                     k+=strlen(gname[j]); 
                     do { 
                       tmp=gidx[j++]; 
                       if ( j > gcount ) 
                               break; 
 
                       buffer[k++]='\t'; 
                       strcpy(&buffer[k],line[tmp]); 
                       k+=strlen(line[tmp]); 
 
                       buffer[k++]='\t'; 
                       if ((l=idle[tmp]/60) != 0) 
                               sprintf(temp,"%d:%d\t",l,(idle[tmp]%60)); 
                       else 
                               sprintf(temp,"%d\t",(idle[tmp]%60)); 
                       strcpy(&buffer[k],temp); 
                       k+=strlen(temp); 
 
 
                       strcpy(temp,asctime(localtime(&time[tmp]))); 
                       strcpy(&buffer[k],temp); 
                       k+=(strlen(temp) - 6); 
 
                       buffer[k++]='\t'; 
                       strcpy(&buffer[k],hhost[tmp]); 
                       k+=strlen(hhost[tmp]); 
 
                       buffer[k++]='\n'; 
                    } while (strcmp(name[tmp],"repeat") == 0); 
                  } 
               } 
               buffer[k++]='\0'; 
        } 
        else { 
                count = -1; 
                buffer[k++] = (char) count; 
        } 
 
        :       :               : 
        :       :               : 
        /* 此处省略要求 Connect 的 Socket 之传送资料部份. */ 
        :       :               : 
        :       :               : 
 

 
        其中 rusers 的部份可在 CCSUN 用 " man 3 rusers " 查, 兹摘录 
如下: 
 
==================> man 3 rusers 的摘录 <============== 
NAME 
     rnusers, rusers - return information about users  on  remote 
     machines 
 
DESCRIPTION 
     rnusers() returns the number of users logged on to host  (-1 
     if  it  cannot  determine  that number).  rusers() fills the 
     utmpidlearr structure with data about host, and returns 0 if 
     successful. 
 
PROGRAMMING 
     #include <rpcsvc/rusers.h>         <=== 查 struct 的地方 
     rnusers(host) 
     char *host 
     rusers(host, up) 
     char *host 
     struct utmpidlearr *up; 
========================================================== 
 
        由於以上的 manual 中并没有指出 utmpidlearr 的结构型态如何, 
因此我们必须列出我们所需要的 head file 资料以取得我们要的 
utmpidlearr 结构. 以下是我的搜寻所得: 
 
==================> utmpidlearr 重要资料 <================= 
struct utmpidle { 
        struct utmp ui_utmp; 
        unsigned ui_idle; 
}; 
 
struct utmpidlearr { 
        struct utmpidle **uia_arr; 
        int uia_cnt; 
}; 
 
struct utmp { 
        char    ut_line[8];             /* tty name */ 
        char    ut_name[8];             /* user id */ 
        char    ut_host[16];            /* host name, if remote */ 
        long    ut_time;                /* time on */ 
}; 
============================================================ 
 
        有了这些资料以後, 再看前面的程式就比较易懂了. ( 若因程式的 
变数命名太差, 或流程太混乱, 请见谅. 因这一部份在完成之初又不断加新 
的功能, 而不是一次完成的. ) 
 
        程式中的 buffer 这个变数储存欲送出的资料, 其格式为: 
================================================================== 
工作站名        login 人数      符合资料的人数     帐号及其上机状态 
any bytes         1 bytes         1 bytes             any bytes 
================================================================== 
 
        以下面 FindMan 的输出为例说明: 
=====================> FindMan 部份输出 <===================== 
ccsun7: 
u813xx07 -----> xxxxxxxxxxx 
        ttyq0   0       Tue Apr 27 23:56:53     xxxuling.Dorm10. 
        ttyp1   0       Wed Apr 28 01:46:29     xxxuling.Dorm10. 
 
u802xx23      Chen2 xxxxxxxx 
        ttyr6   31:47   Mon Apr 26 18:47:17     140.113.1xx.177: 
 
ccsun16: 
u813xx16 -----> xxxxxxxxxxx 
        ttyp1   0       Wed Apr 28 01:46:29     xxxmy.DormChu.NC 
============================================================== 
 
        其中工作站名不限 byte 数, 接收端以 ":\n" 判断此部份的资料 
结束与否. 当第二部份为 0 时即填入 -1 表示无人, 与资料比对後找不到 
人亦如此. check 函数即是处理与资料比对的工作, FindMan 是与 .look 
比对, ScanGirl 与 girl 的资料档比对. check 的函数传回 gcount、 
gname、gidx 三个变数. gcount 即是 match 的人数, gname 是从 rusers 
传回的资料档稍作修改 ( 重复的帐号改成 "repeat" ) 而成. 而 gidx 是 
rusers 传回资料的排序後的 index. 
        从 check 函数传回的 gname、gidx 构成 buffer 阵列最後的资料. 
即 "帐号及其上机状态" 部份. 全部完成後即将资料送出. 由於 check 函数 
并不难写, 故不列出. 
 
        由於篇幅及时间所限, 这次只讲 pitch 函数, 其它以後再继续, 
下期见!! 8-) 
 
————————————————————————————————— 
FindMan 关闭启示: 
    近来 CCSUN 的使用率大幅增加 , 使得 CCSUN 
的 Load 高居不下, 我的 FindMan 公用程式只有在 Load 很轻的 
SUN 上测试过 ( 0 到 2 ), 没想到最近 Load 重的 SUN ( 7 以上 ) 
上执行时, 我程式中加快搜寻速度的部份竟成为致命伤.  由於一 
次开二十个程序, 若不幸因电脑异常, 则大部分程序会停住而无法离开, 
使电脑 Load 更形加重, 也令系统管理者困扰. 在我花了十数小时不断 
改程式後( 包括加上 Alarm Signal 控制执行时间 ), 终於还是不能克服 
Load 重时的异常状况. 看来, 我的程式理念 ( 以多个程序平行处理来增 
快速度 ) 只能在人数少的工作站或特殊的电脑才能用. 有志於发展应用程 
式的同学, 切记这个教训. 
 
        由於旧的 FindMan 程式有时会出状况, 我已经将它去掉, 
以後有空时再写新的单一程序之 FindMan. 虽然程式已撤掉, 但本文可当 
成纯为讨论程式设计, 故仍继续下去. 
————————————————————————————————— 

BBS水木清华站∶精华区