Linux网络编程学习(三) ----- 进程控制实例(第三章)

本节主要介绍一个进程控制的实例,功能就是在前台或者后台接收命令并执行命令,还能处理由若干个命令组成的命令行,该程序命名为samllsh。

基本逻辑就是

while(EOF not typed)
{
从用户终端取得命令行
执行命令
}

setp1:取得命令行内容,用uerin函数实现,处理步骤首先显示提示符,提示符的具体内容由用户通过参数传递给函数,然后每次从键盘读取一个字符,存入inpbuf中,结束时userin返回字符个数或者EOF(文件结尾),换行符也要存入inpbuf

代码如下:

#include "smallsh.h"
/* 程序缓冲区和指针 */
static char inpbuf[MAXBUF],tokbuf[2*MAXBUF],
*ptr = inpbuf,*tok = tokbuf;
/* userin()函数 */
int userin(chat* p)
{
int c,count;
ptr = inpbuf;
tok = tokbuf;
/* 显示提示 */
printf("%s ",p);
for (count = 0;;)
{
if ((c=getchar())==EOF)
return(EOF);
if (count < MAXBUF)
inpbuf[count++] = c;
if (c =='\n' && count < MAXBUF)
{
inpbuf[count] = '\0';
return(count);
}
/* 如果行过长重新输入 */
if (c == '\n')
{
printf("smallsh:input line too long\n");
count=0;
printf("%s ",p);
}
}
}

  其中的头文件samllsh.h内容为

#include <stdio.h>
#define EOL 1 /* 行结束 */
#define ARG 2
#define AMPERSAND 3
#define SEMICOLON 4
#define MAXARG 512 /* 命令行参数个数的最大值 */
#define MAXBUF 512 /* 输入行的最大长度 */
#define FOREGROUND 0
#define BACKGROUND 1

  step2:从userin构造的命令行缓冲区中分析出命令名和参数,采用gettok函数,其中的tptr是一个字符型指针,调用后该指针指向实际的解析出的内容,调用方法是toktype = gettok(&tptr)

int gettok(char* output)
{
int type;
outptr = tok;
/* 首先去除空白字符 */
for (;*ptr==''||*ptr=='\t';ptr++)
{
*tok++ = *ptr;
} switch(*ptr++)
{
case '\n':
type=EOL;
break;
case '&':
type=AMPERSAND;
break;
case ';':
type=SEMICOLON;
break;
default:
type=ARG;
while (inarg(*ptr))
{
*tok++ = *ptr++;
} }
*tok++ = '\0';
return (type);
}

  step3:采用函数inarg用于确定一个字符是否可以作为参数的组成符,检查字符是否是smallsh的特殊字符,代码如下

static char special[]={‘‘,’\t’,’*’,’;’,’\n’,’\0’};
int inarg(char c)
{
char *wrk;
for (wrk = special;*wrk != ’\0’;wrk++)
{
if (c == *wrk) return(0);
}
return(1);
}

  step4:程序procline使用函数gettok()分析命令行,处理过程中构造一张参数表,当遇到换行符或者分号时,就调用runcommand来执行被分析的命令行,假设已经用userin读入了一个输入行

#include "smallsh.h"
void procline()
{
char * arg[MAXARG+1];
int toktype;
int narg;
int type;
for(narg = 0;;)
{
switch(toktype = gettok(&arg[narg]))
{
case ARG:
if (narg<MAXARG)
narg++;
break:
case EOL:
case SEMICOLON:
case AMPERSAND:
type = (toktype==AMPERSAND)?BACKGROUND:FOREGROUND;
if (narg != 0)
{
arg[narg] = NULL;
runcommand(arg,type);
}
if (toktype==EOL)
return;
narg=0;
break;
}
}
}

  step5:函数runcommand,实现启动命令进程,入参为一个整型参数where,如果where被设置为BACKGROUND,那么将忽略wait()的调用,并且runcommand只显示进程标识符就返回。wait()返回的是第一个结束的子进程的进程标识符,而不是最后一个被启动的子进程的进程标识符。

execvp()表明按当前环境变量Path中的目录来搜索命令中表明的程序文件

#include "smallsh.h"
int runcommand(char** cline,int where)
{
int pid,exitstat,ret;
if((pid = fork()) < 0)
{
perror("fork fail");
return(-1);
}
if (!pid)
{ /* 子进程代码 */
execvp(*cline,cline);
perror(*cline);
exit(127);
}
/* 父进程代码 */
/* 后台进程代码 */
if (where==BACKGROUND)
{
printf("[process id %d]\n",pid);
return(0);
}
/* 前台进程代码 */
while ((ret = wait(&exitstat))!= pid && ret != -1) ;
return (ret==-1?-1:exitstat);
}

  step6:最后就是main函数了

#include "smallsh.h"
char *prompt = "command>";
void main()
{
while (userin(prompt)!=EOF)
{
procline();
}
}

  

上一篇:【雅虎2017】一个在线展示广告的CVR预估框架实践


下一篇:ABP框架实践基础篇之开发UI层