前言:
喔,终于熬过了期末考和实习,终于有属于自己的时间了,为了巩固之前的知识,就特此编写一个程序来实现这个功能;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的子进程没有收到信号;当时困惑了许久,甚至想放弃这个方法,后面询问了老师,才得到解决,也让我印象非常深刻;