Linux下多进程编程小例——获取网卡的IP地址

Linux下多进程编程的核心是调用fork()系统调用用来创建一个新的进程:
pid_t   fork(void);  
由fork()创建的新进程被称为子进程。fork()函数被调用一次,但有两次返回。 
返回值=0:  子进程              
返回值>0:  父进程,返回值为子进程的进程ID。  
返回值<0:  出错 
1,子进程可以通过getpid()和getppid()分别获取自己的进程ID和父进程ID; 
2,一个父进程可以有很多个子进程,没有一个系统调用可以获取所有的子进程ID,所以需要将子进程的ID通过返回值的形式传递给父进程。
 
阅读以下代码你需要了解的函数与系统调用:
dup2()    execl()      wait()      lseek()      pipe(fd)      popen()   
strstr()    strchr()   strrchr()    strncpy()     strncpy()   memset()
 
 
利用多进程编程获取网卡eth0的IP地址
方法一(利用文件I/O):

子进程执行ifconfig eth0,将执行的结果输出重定向到文件(.ipc.log)中,父进程再从该文件中读出ip地址。

/*********************************************************************************
*      Copyright:  (C) 2018 wangtao
*                  All rights reserved.
*
*       Filename:  fork.c
*    Description:  This file
*                 
*        Version:  1.0.0(05/11/2018)
*         Author:  WangTao <TAlicer@163.com>
*      ChangeLog:  1, Release initial version on "05/11/2018 06:09:56 PM"
*                 
********************************************************************************/

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define IPC_FILE ".ipc.log"
/********************************************************************************
*  Description:
*   Input Args:
*  Output Args:
* Return Value:
********************************************************************************/
int main (int argc, char **argv)
{
    pid_t  pid;
    int    fd = -1;
    char   buf[512];
    FILE   *fp = NULL;

    fd = open(IPC_FILE, O_RDWR|O_CREAT|O_TRUNC,0644);    //打开.ipc.log并获取文件描述符fd
    if( fd < 0)
    {
        printf("open file '%s' failure: %s\n",IPC_FILE,strerror(errno));
        return 0;
    }

    pid=fork();                           //调用fork创建子进程
    if(pid <0)
    {
       printf("fork() error: %s\n",strerror(errno));
       return 0;
    }

    else if(pid == 0)    //###"子进程"###
    {
       dup2(fd,1);       //在子进程中,将标准输出重定向到.ipc.log文件中(将标准输出(1)关掉,再将.ipc.log的文件描述符改为1)
       execl("/sbin/ifconfig","ifconfig","eth0",NULL);  //调用execl执行新的程序(命令ifconfig eth0)
       printf("####haha\n");     //该句不会打印
    }

    else if(pid > 0)    //###"父进程"###
    {
       int     status;
       wait(&status);       //等待子进程退出后,再继续向下执行

       printf("Parent running: child pid[%ld],parent pid[%ld],grandparent pid[%ld]\n",pid,getpid(),getppid());
       
       lseek(fd,0,SEEK_SET);   //将文件偏移量设置为0,不然读到为空
       fp = fdopen(fd,"r");                   //将文件描述符转换为文件流
      // while( read(fd,buf,sizeof(buf))>0 )
       while( fgets(buf,sizeof(buf),fp)>0 )   //将.ipc.log里的内容一行一行的读到buf里
       {
         if( strstr(buf,"inet addr:"))        //如果读到的某一行buf含有关键词"inet addr:",则打印该次buf里的内容
         {
           printf("buf:%s\n",buf);
         }
       }
    }

    close(fd);
    unlink(IPC_FILE);    //删除文件.ipc.log

    return 0;
} /* ----- End of main() ----- */

程序执行结果:

 

方法二(利用管道):
先创建管道,再创建子进程,这样父进程和子进程都拥有了管道的读端与写端,然后关闭子进程管道读端,关闭父进程写端,子进程执行ifconfig eth0,将执行的结果重定向到管道写端,父进程再从管道读端里获取IP地址。
/*********************************************************************************
*      Copyright:  (C) 2018 wangtao
*                  All rights reserved.
*
*       Filename: fork_pipe.c
*    Description:  This file
*                 
*        Version:  1.0.0(05/11/2018)
*         Author:  WangTao <TAlicer@163.com>
*      ChangeLog:  1, Release initial version on "05/11/2018 06:09:56 PM"
*                 
********************************************************************************/

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<unistd.h>

/********************************************************************************
*  Description:
*   Input Args:
*  Output Args:
* Return Value:
********************************************************************************/
int main (int argc, char **argv)
{
    pid_t  pid;
    int    fd[2];
    char   buf[512];
    FILE   *fp = NULL;

    if( pipe(fd)<0 )               //调用pipe创建管道, fd参数返回两个文件描述符,fd[0]指向管道的读端,fd[1]指向管道的写端。fd[1]的输出是fd[0]的输入。
    {
       printf("pipe failure: %s\n",strerror(errno));
       return -1;
    }

    pid=fork();                      //调用fork创建子进程
    if(pid <0)
    {
       printf("fork() error: %s\n",strerror(errno));
       return 0;
    }

    else if(pid == 0)     //###"子进程"###
    {  
       close(fd[0]);      //关闭管道读端
       dup2(fd[1],1);     //在子进程中,将标准输出重定向到管道写端中(将标准输出(1)关掉,再将管道写端的文件描述符改为1)
       execl("/sbin/ifconfig","ifconfig","eth0",NULL);       //调用execl执行新的程序(命令ifconfig eth0)
       printf("####haha\n");  //该句不会打印
    }

    else if(pid > 0)     //###"父进程"###
    {  
       close(fd[1]);     //关闭管道写端
       int     status;
       wait(&status);

       printf("Parent running: child pid[%ld],parent pid[%ld],grandparent pid[%ld]\n",pid,getpid(),getppid());
       
       fp = fdopen(fd[0],"r");                   //将文件描述符转换为文件流

       while( fgets(buf,sizeof(buf),fp)>0 )     // 将父进程管道读端里的内容一行一行的读到buf里
       {
         if( strstr(buf,"inet addr:"))
         {
           printf("buf:%s\n",buf);
         }
       }
       fclose(fp);

    }
    return 0;
} /* ----- End of main() ----- */
程序执行结果:
方法三(利用popen函数)推荐:
popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c来执行ifconfig eth0    第二个参数“r”代表读取
/*********************************************************************************
*      Copyright:  (C) 2018 Wang Tao
*                  All rights reserved.
*
*       Filename:  popen.c
*    Description:  This file
*                 
*        Version:  1.0.0(2018年05月12日)
*         Author:  wang tao <TAlicer@163.com>
*      ChangeLog:  1, Release initial version on "2018年05月12日 21时14分17秒"
*                 
********************************************************************************/
#include <stdio.h>
#include <string.h>
#include <errno.h>
/********************************************************************************
*  Description:
*   Input Args:
*  Output Args:
* Return Value:
********************************************************************************/
int main (int argc, char **argv)
{
    FILE   *fp;
    char   buf[512];
    char   *p1,*p2,*p3;
    char   ipaddr[16];
    char   netmask[16];

    fp = popen("ifconfig eth0","r");
    if( fp == NULL)
    {
      printf("popen failure: %s\n",strerror(errno));
      return 0;
    }

    while( fgets(buf,sizeof(buf),fp)>0)
    {
      if( (p1=strstr(buf,"inet addr:")) !=NULL)  //p1指向含有"inet addr:"关键词这一行的首地址
      {

          //printf("%s",buf);

          p2=strchr(p1,':');   //p2指向p1行第一个冒号处
          p3=strchr(p2,' ');   //p2指向p2以后第一个空格处
          memset(ipaddr,0,sizeof(ipaddr));
          strncpy(ipaddr,p2+1,p3-p2);      //截取IP地址到ipaddr数组中
          printf("IP address: %s\n",ipaddr);
         
          p2=strrchr(p1, ':');   //p2指向p1行最后一个冒号处
          p3=strrchr(p2, '\n');  //p3指向p2以后最后一个换行符处(在p1行中)
          memset(netmask, 0, sizeof(netmask));
          strncpy(netmask, p2+1, p3-p2);    //截取Mask地址到netmask数组中
          printf("Netmask address: %s\n", netmask);
      }
    }
    pclose(fp);

    return 0;
} /* ----- End of main() ----- */
程序执行结果:

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值