GPRS--手动拨号编程

前言:

    喔,终于熬过了期末考和实习,终于有属于自己的时间了,为了巩固之前的知识,就特此编写一个程序来实现这个功能;ps:程序本就是用来替代人手动的过程嘛。

    前面我们实现了手动拨号上网,因此熟悉了拨号上网的流程,因此我们可以用程序来实现这个流程。拨号流程:1.工具准备2.软件准备3.连接准备4.手动拨号连接5.检查连接是否成功6.断开连接具体细节可参考我的pppd拨号连接博客:https://blog.csdn.net/PipiAvenger/article/details/80696680

 

程序如下:


 

/********************************************************************************
*      Copyright:  (C) 2018 guozhihao
*                  All rights reserved.
*
*       Filename:  gprs_ppp.h
*    Description:  头文件
*
*        Version:  1.0.0(07/04/2018)
*         Author:  Guozhihao <810170156@qq.com>
*      ChangeLog:  1, Release initial version on "07/04/2018 12:50:14 AM"
*                 
********************************************************************************/

#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>

typedef struct _PID                //定义结构体类型
{
    long    child_pid;
}PID;                                        //变量为PID

PID *init_func_PID();                //初始化结构体函数声明

int pppd_on(PID *program_PID,const char *location,const char *script);    //拨号连接函数

int pppd_OFF(PID *program_PID);        //断开拨号连接函数

int check_pppd_connect(PID *program_PID);    //检查程序状态函数

 

 


 

/*********************************************************************************
*      Copyright:  (C) 2018 guozhihao
*                  All rights reserved.
*
*       Filename:  gprs_ppp.c
*    Description: 一键自动拨号上网
*                 
*        Version:  1.0.0(06/30/2018)
*         Author:  Guozhihao <810170156@qq.com>
*      ChangeLog:  1, Release initial version on "06/30/2018 09:32:43 PM"
*                 
********************************************************************************/
#include "gprs_ppp.h"


/*
*  这种函数初始化方式好处在于不需要使用者在额外定义一个结构体,只需要简单的定义一个对应* 类型的函数指针,然后通过该函数的返回值来赋值给定义的函数指针即可;
*/
PID *init_func_PID()
{
    PID         *init_PID =NULL;                        //定义一个指向PID变量的函数指针
    
    if( NULL == (init_PID = (PID *)malloc(sizeof(PID))) )                //使用malloc函数进行分配空间
    {
        return NULL;
    }

    memset(init_PID,0,sizeof(init_PID));        //清空函数指针所指向的地址里面的内容

    return init_PID;                                         //返回PID类型的函数指针

}
/********************************************************************************
*  Description:
*   Input Args:第一参数传递的是函数指针,第二参数传的拨号程序pppd位置,第三参数传的是拨号脚本的位置;
*  Output Args: program_PID->child_pid
* Return Value:返回值=0 程序正常退出,<0程序异常退出;
********************************************************************************/
int pppd_on(PID *program_PID,const char *location,const char *script)
{
    pid_t           pid;
    
    if( NULL == program_PID )                                        //判断传参是否进过函数初始化
    {
        printf("ERROR:program_PID function is NULL\n" );
    }

    if( (pid = fork()) < 0)                                                   //使用fork函数来创建子进程
    {
        printf("Error:fork failure !\n");
        return -2;

    }
    else if(pid == 0)                                                         //子进程执行语句
    {
        int     fd ;
        printf("Start to perform pppd program!\n");

#if 0
        daemon(0,0);          //标注bug
     
        printf("Start to perform pppd program!\n");
        
        close(STDOUT_FILEON);
        
        fd = open("gprs_ppp.log",O_CREAT | O_RDWR ,0755);
        if( fd < 0 )
        {
            printf("open failure:%s\n",strerror(errno));
            return -6;
        }
#endif
        execl(location,"pppd","call",script,NULL);           //调用execl去执行pppd程序
        
    }else if(pid > 0)                                                        //父进程获取子进程号并且赋值保存到结构体当中去;
    {
        program_PID->child_pid = pid;
        printf("parent pid = %ld, child pid = %ld\n",(long)getpid(),(long)program_PID->child_pid);
    }
    return 0 ;
}
/********************************************************************************
*  Description:断开pppd拨号软件的拨号上网功能
*   Input Args:program_PID函数指针
*  Output Args:program_PID函数指针
* Return Value:返回值<0,函数退出异常。返回值=0,函数正常退出;
********************************************************************************/

int pppd_OFF(PID *program_PID)
{
    int             result;

    printf("now start to close program:%ld \n",(long) program_PID->child_pid);

    if( kill( (int) program_PID->child_pid,SIGINT) )                    //使用父进程调用kill函数来发送打断信号给另外一个程序也就是pppd程序
  
        printf("Send kill signal to child program error!\n");
        return -3;
    }

    printf("Start to exit the program!\n");

    return 0;

}

/* 释放函数指针所指向的结构体 */
void free_func_PID(PID *program_PID)
{
    free(program_PID);    //由于函数初始化调用了malloc函数,故需要free,否则容易导致内存泄漏;
}
/********************************************************************************
*  Description:检查pppd状态,可用于查询pppd拨号是否成功
*   Input Args:
*  Output Args:
* Return Value:
********************************************************************************/
int check_pppd_connect(PID *program_PID)
{
    int         i = 0;

    FILE        *fp;
    
    fp = popen("ifconfig ppp0","r");            //通过管道的方式调用shell来执行ifconfig命令
    if( !fp )
    {
        printf("Connect time out !\n");
        
        pppd_OFF(program_PID);

        return -7;
    }


    printf("Connect successful!\n");
    return 0;
}

 


 


/*********************************************************************************
*      Copyright:  (C) 2018 guozhihao
*                  All rights reserved.
*
*       Filename:  gprs_ppp_main.c
*    Description:  拨号主函数ps:main函数
*                 
*        Version:  1.0.0(07/02/2018)
*         Author:  Guozhihao <810170156@qq.com>
*      ChangeLog:  1, Release initial version on "07/02/2018 02:38:24 AM"
*                 
********************************************************************************/
#include "gprs_ppp.h"

/********************************************************************************
*  Description:主函数,用于调用各个函数功能的程序入口
*   Input Args:argc,**argv
*  Output Args:NULL
* Return Value:返回值<0,函数执行出错;返回值=0,函数正常退出
********************************************************************************/
int main (int argc, char **argv)
{   
    int             result;
    
    PID             *program_PID = NULL;

    program_PID = (PID *)init_func_PID();            //1.初始化
    if(NULL == program_PID )
    {
        printf("init program_PID error!\n");
        goto Cleanup;
    }


    result = pppd_on(program_PID,"/GPRS/ppp/pppd","wcdma");    //2.打开pppd拨号连接
    if(result < 0)
    {
        printf("ERROR: pppd_on failure!\n");
        return -1;
    }
    
    while( 'c' == getchar() )
    {
        result = check_pppd_connect(program_PID);        //3.检查pppd拨号程序是否成功上网
        if(result < 0)
        {
            return 0;
        }
    }

    while( 'q' == getchar() )
    {
        printf("Now start to quit pppd \n");

        result = pppd_OFF(program_PID);                        //4.退出拨号程序
        if(result < 0)
        {
            printf("ERROR: pppd_OFF failure!\n");        
            return -2;
        }
    }
    
    free_func_PID(program_PID);
    return 0;

Cleanup:
    free_func_PID(program_PID);

    return 0;

} /* ----- End of main() ----- */

 

编程是遇到过的问题分享:

    fork的迷惑:

    在调用fork时,一直不明白fork执行后会有两个的返回值(一个为子进程,一个为父进程),而子进程的特点就在于:操作子进程的方式就是在pid==0的那个{}之中,之外就是父进程执行的内容。如果让子进程调用execl函数时,他会抛弃从父进程那继承而来的所有数据段等信息(进程号不变),覆盖的是执行程序对应的数据段等。

    daemon函数的错用:

    fork函数产生的子进程默认在后台运行也就不需要在调用daemon函数,而且调用daemon函数会导致僵尸(Z)进程,而且通过ps命令会发现程序创建了2个子进程(一共3个子进程)而我的断开拨号函数所发送的信号只到达调用daemon函数(本质也是创建一个新的子进程去执行)的那个子进程,而真正在运行pppd的子进程没有收到信号;当时困惑了许久,甚至想放弃这个方法,后面询问了老师,才得到解决,也让我印象非常深刻;

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值