曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 5355|回复: 1
打印 上一主题 下一主题

[进程] 计划工具(挂电驴用:)

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2009-10-12 01:34:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
因为共享网线,一挂电驴,全网瘫痪,所以只能挑夜间无人上网时才挂电驴。但挂一定时间后,需自动结束电驴进程,以免有人起来后上网,你的电驴还挂着,同样影响别人的利益。所以,程序的功能是:自定义要启动的程序名称,自定义程序启动时间,自定义关闭程序时间。在程序里,只要输入程序的名字即可运行(但没有处理绝对路径,相对路径这些情况,只支持标准路径里的程序)。

实现代码如下
#include <time.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>

#define NAME_SIZE    256
char name_buffer[NAME_SIZE];
int    start_hour;
int    start_minute;
int    stop_hour;
int    stop_minute;
struct tm *tm_ptr;
int main()
{
    pid_t    pid;
    time_t the_time;
    char command [64];
    char appid [64];
    int  id;
    FILE *fd;

    printf ("请输入程序启动时间(小时):");
    scanf ("%d", &start_hour);
    if (start_hour > 24 || start_hour < 0) {
        printf ("输入小时错误!\n");   
        exit (1);
    }
    printf ("\n");
   
    printf ("请输入程序启动时间(分钟):");
    scanf ("%d", &start_minute);
    if (start_minute > 59 || start_minute < 0) {
        printf ("输入分钟错误!\n");   
        exit (1);
    }
    printf ("\n");
   
    printf ("请输入程序停止时间(小时):");
    scanf ("%d", &stop_hour);
    if (stop_hour > 24 || stop_hour < 0) {
        printf ("输入小时错误!\n");   
        exit (1);
    }
    printf ("\n");

    printf ("请输入程序停止时间(分钟):");
    scanf ("%d", &stop_minute);
    if (stop_minute > 59 || stop_minute < 0) {
        printf ("输入分钟错误!\n");   
        exit (1);
    }
    printf ("\n");

    printf ("请输入要启动程序的名称:");   
    scanf ("%s", name_buffer);
    name_buffer [sizeof (name_buffer) - 1] ='\0';
    printf ("要启动的程序为: %s", name_buffer);
    printf ("\n");

    while (1) {
        time (&the_time);
        tm_ptr = gmtime (&the_time);
        printf ("当前时间: %02d:%02d:%02d\n", tm_ptr->tm_hour + 8, tm_ptr->tm_min, tm_ptr->tm_sec);
       
    if ((tm_ptr->tm_hour + 8) == start_hour && tm_ptr->tm_min == start_minute)
            break;
       
        sleep (1);
    }   

    pid = fork();
    switch (pid) {
        case -1:
           perror ("fork failed");
           exit (1);
       
        case 0:
           system (name_buffer);
           break;

        default:
           while (1) {
            (void) time (&the_time);
            tm_ptr = gmtime (&the_time);
           
            if ((tm_ptr->tm_hour + 8) == stop_hour && tm_ptr->tm_min == stop_minute)
                break;
           
            sleep (1);
         }
           sprintf (command, "ps -A -o pid,comm |grep %s |awk '{print $1}'", name_buffer);
           if ((fd = popen (command, "r")) == NULL) {
            perror ("popen");
            exit (EXIT_FAILURE);
           }
           fgets (appid, 64, fd);
           id = atoi (appid);

           if (kill (id, SIGKILL) == -1) {
            perror ("kill");
            exit (EXIT_FAILURE);
          }       
           break;
    }
   
    exit (0);
}

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
沙发
 楼主| 发表于 2009-10-12 02:33:34 | 只看该作者

程序说明

一开始设定 2 个时间,分别是启动程序时间与关闭程序时间,在设定时间时,分别对时间的输入做了出错检测。

接着,要求输入要启动的程序,比如启动 amule 电驴,就直接输入 amule 。在处理输入时,使用了 scanf() 函数,这个函数并没有对输入的数据做溢出检查。安全的做法是使用 fgets() 函数。如果使用 fgets() 函数,那么则有一个需要注意地方:

假如仅仅使用 fgets() 函数,那么会发现,程序没有被阻塞等待用户输入任何数据,而是直接往下跑。这个现象的原因是,在输入最后一个停止时间(分钟)时,一个回车符仍留在标准输入缓冲区中,这时在执行到 fgets() 函数时,该函数会直接读到这个换行符,而造成 fgets() 服阻塞的现象。但不能认为在 fgets() 前面加一个 fflush() 就能解决问题,fflush() 函数的作用是把缓冲区中的数据强制刷到它参数指定的流当中,但并不表名缓冲区中的数据在使用它后就会消失(仍然在)!所以,如果使用 fgets() 函数,那么就要在 fgets() 之前用一个 fgetc() 函数,让这个函数把缓冲区内的换行符读走,那么当程序执行到 fgets() 时,就会看到 ”阻塞“ 了。

在输入程序名后,开始以每秒为1个周期的检查计时,如果发现系统时间等于设定时间,则跳出时间检查。gmtime() 得到的时间是格林威治时间,北京时间的小时数比格林威治时间多 8 ,所以上面需要 tm_ptr->tm_hour + 8 。

在定时到后,程序会 fork() 出一个子进程。在这个子进程里要做的事情就是启动想要启动的程序,这里用的是函数 system() 来实现。当要启动的程序确实存在时,会正常启动。实际上,system() 函数底层是利用 exec 函数来启动程序。所以子进程“消亡”了,此后进入到的是被启动的程序空间里。

当程序返回到父进程里时,父进程会做定时的检查,如果结束任务的时间到了,则会结束启动的程序,这个过程是这样的:

sprintf (command, "ps -A -o pid,comm |grep %s |awk '{print $1}'", name_buffer);   
使用 sprintf() 函数构造了一个 shell 命令,如果说要启动的程序是电驴 amule ,那么这个 shell 命令就会被够造成:
ps -A -o pid, comm | grep amule |awk '{print $1}'
ps 命令中,-A 参数表示列出所有进程信息。
-o 参数后面跟着自定义的栏,这里是 pid 和 comm 。pid 和 comm 需要用逗号隔开。然后通过 grep 命令过滤出要结束的程序,接着再通过 awk 过滤出 pid 值。注意的是,这里的 pid 值是以字符串的形式存在的,所以要用 atoi() 函数来转换。

得到 pid 信息,是利用了 popen() 函数创建的管道来实现的。这个管道是调用进程和 popen() 中 command 参数命令所对应的程序间的一条通道。也就是说,通过这条管道,可以得到脚本命令的执行结果。冠于 popen() 见:http://www.groad.net/bbs/read.php?tid-1245.html

最后通过 kill 函数来杀死要结束的进程。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-3 10:52 , Processed in 0.080178 second(s), 21 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表