本节主要介绍一个进程控制的实例,功能就是在前台或者后台接收命令并执行命令,还能处理由若干个命令组成的命令行,该程序命名为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();
}
}

  

Linux网络编程学习(三) ----- 进程控制实例(第三章)的更多相关文章

  1. Linux网络编程学习(二) ----- 进程控制(第三章)

    1.进程和程序 程序是一个可执行文件,而一个进程是一个执行中的程序实例.一个进程对应于一个程序的执行,进程是动态的,程序是静态的,多个进程可以并发执行同一个程序.比如几个用户可以同时运行一个编辑程序, ...

  2. Linux网络编程学习(八) ----- 文件和记录锁定(第四章)

    1.什么是文件和记录锁定? 文件锁定的是整个文件,而记录锁定只锁定文件的一部分,文件和记录锁分为咨询式锁定和强制锁定 1)咨询式锁定 某个进程对某个文件进行了咨询式锁定,其他想访问该文件的进程将会被操 ...

  3. Linux网络编程学习计划

    由于网络编程是很重要的一块,自己这一块也比较欠缺,只知道一些皮毛,从今天开始系统学习<Linux网络编程>一书,全书分为十四个章节: 第一章   概论   P1-16 第二章   UNIX ...

  4. Linux网络编程学习路线

    转载自:https://blog.csdn.net/lianghe_work/article 一.网络应用层编程   1.Linux网络编程01——网络协议入门 2.Linux网络编程02——无连接和 ...

  5. Linux网络编程——原始套接字实例:MAC 头部报文分析

    通过<Linux网络编程——原始套接字编程>得知,我们可以通过原始套接字以及 recvfrom( ) 可以获取链路层的数据包,那我们接收的链路层数据包到底长什么样的呢? 链路层封包格式 M ...

  6. Linux网络编程学习(四) -----守护进程的建立(第三章)

    本文介绍一个例程daemon_init() #include <sys/types.h> #include <signal.h> #include <unistd.h&g ...

  7. Linux网络编程学习(九) ----- 消息队列(第四章)

    1.System V IPC System V中引入的几种新的进程间通信方式,消息队列,信号量和共享内存,统称为System V IPC,其具体实例在内核中是以对象的形式出现的,称为IPC 对象,每个 ...

  8. linux网络编程学习笔记之五 -----并发机制与线程�

    进程线程分配方式 简述下常见的进程和线程分配方式:(好吧,我仅仅是举几个样例作为笔记...并发的水太深了,不敢妄谈...) 1.进程线程预分配 简言之,当I/O开销大于计算开销且并发量较大时,为了节省 ...

  9. linux网络编程学习笔记之四 -----多-threaded服务器

    对于使用过程中并发.通过实现更轻量级线程. 每个线程都是一个独立的逻辑流. 主题是CPU在执行调度的最小独立单位,这个过程是资源分配单元.当然,这是在微内核操作系统说.总之,这是唯一的一个操作系统内核 ...

随机推荐

  1. 5.Fiddler模拟弱网限速方法

    原理:Fiddler的模拟限速是在客户端请求前来自定义限速的逻辑,此逻辑是通过延迟发送数据或接收的数据的时间来限制网络的下载速度和上传速度,从而达到限速的效果. 算法:那么我们的算法就是 1000/下 ...

  2. Python导入jar包

    一.环境准备 1.Python 3.6 64位+jre 64位+win64位(jre和Python位数一致) 2.安装jpype,安装的时候输入 pip install jpype1 2.1安装提示e ...

  3. Linux监控平台、安装zabbix、修改zabbix的admin密码

    1.Linux监控平台 2. zabbix监控 3.zabbix的安装下载:wget -c https://repo.zabbix.com/zabbix/3.4/rhel/7/x86_64/zabbi ...

  4. MySQL数据库-pymysql模块操作数据库

    pymysql模块是python操作数据库的一个模块 connect()创建数据库链接,参数是连接数据库需要的连接参数使用方式: 模块名称.connect() 参数: host=数据库ip port= ...

  5. django admin 支持时间更改

    from django.db import models import django.utils.timezone as timezone class Doc(models.Model): add_d ...

  6. zabbix_agent添加到系统服务启动(八)

    Centos6.5上安装了zabbix_agent后,需要把zabbix_agent添加到系统服务启动,要不然每次要一长串路径再启动,挺麻烦的. 步骤: 1)拷贝zabbix解压包里的zabbix_a ...

  7. cpgf如何实现lua script binding的?

    Lib: https://github.com/cpgf/cpgf/tree/master 代码 以下是operator的实现函数 int UserData_operator(lua_State * ...

  8. 【java】设计模式-单例设计模式

    单例设计模式:解决一个类在内存中是存在一个对象的问题.当需要该事物的对象在内存中唯一时,将以下三步添加即可. 思想:想要保证对象唯一1.为了避免其他程序过多的建立该类对象,先禁止其他程序建立该类对象2 ...

  9. Hadoop-HBASE 热添加新节点

    Hadoop-HBASE 热添加新节点 环境:192.168.137.101 hd1192.168.137.102 hd2192.168.137.103 hd3192.168.137.104 hd4四 ...

  10. MySQL创建数据库与用户

    root远程访问授权 mysql> SHOW DATABASES; +--------------------+ | Database           | +---------------- ...