20135323符运锦-----信息安全系统设计基础第十二周学习总结

本文深入探讨了C语言中的进程控制与通信技术,包括exec系列函数、fork、wait、信号处理、环境变量设置、有名管道FIFO及信号捕捉等核心概念。通过多个实例代码的解析,详细阐述了这些技术的实现原理与应用技巧。
摘要由CSDN通过智能技术生成

学习时间:共10小时
读书:0
代码:7
作业:0
博客:3

实践任务--process

一、exec1.c

程序调用execvp:arglist是命令行的字符串数组,数组的第一个元素为程序名称,最后一个元素必须是null。

#include <stdio.h>
#include <unistd.h>

int main()
{
char    *arglist[3];

arglist[0] = "ls";
arglist[1] = "-l";
arglist[2] = 0 ;//NULL
printf("* * * About to exec ls -l\n");
execvp( "ls" , arglist );
printf("* * * ls is done. bye");

return 0;
}

`
745401-20151129164010860-192995704.png

exec2与exec1的区别就在于:execvp( arglist[0] , arglist ),不过这两个等价,所以运行结果是并无不同。

二、exec2.c

#include <stdio.h>
#include <unistd.h>

int main()
{
char    *arglist[3];
char    *myenv[3];
myenv[0] = "PATH=:/bin:";
myenv[1] = NULL;

arglist[0] = "ls";
arglist[1] = "-l";
arglist[2] = 0 ;
printf("* * * About to exec ls -l\n");
//  execv( "/bin/ls" , arglist );
//  execvp( "ls" , arglist );
//  execvpe("ls" , arglist, myenv);

execlp("ls", "ls", "-l", NULL);
printf("* * * ls is done. bye\n");
}

execlp()函数属于exec()函数族,它是execve(2)函数的前端。

execlp从PATH 环境变量中查找文件并执行。execlp()会从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后将第二个以后的参数当做该文件的argv[0]、argv[1]……,最后一个参数必须用空指针(NULL)作结束。

如果用常数0来表示一个空指针,则必须将它强制转换为一个字符指针,否则将它解释为整形参数,如果一个整形数的长度与char * 的长度不同,那么exec函数的实际参数就将出错。

函数调用成功,最后一句* * * ls is done. bye并未出现。
745401-20151129164804235-90600227.png

三、forkdemo1

#include    <stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
int ret_from_fork, mypid;
mypid = getpid();              
printf("Before: my pid is %d\n", mypid);
ret_from_fork = fork();
sleep(1);
printf("After: my pid is %d, fork() said %d\n",
        getpid(), ret_from_fork);

return 0;
}

这个代码先是打印进程pid,然后调用fork函数生成子进程,休眠一秒后再次打印进程id,这时父进程打印子进程pid,子进程返回0。
745401-20151129165239000-265564407.png

四、forkdemo2

#include <stdio.h>
#include <unistd.h>

int main()
{
printf("before:my pid is %d\n", getpid() );
fork();
fork();
printf("aftre:my pid is %d\n", getpid() );

return 0;
}

代码调用两次fork
745401-20151129165549485-398497360.png

五、forkdemo3

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

int main()
{
int fork_rv;

printf("Before: my pid is %d\n", getpid());

fork_rv = fork();       /* create new process   */

if ( fork_rv == -1 )        /* check for error  */
    perror("fork");
else if ( fork_rv == 0 ){ 
    printf("I am the child.  my pid=%d\n", getpid());

    exit(0);
}
else{
    printf("I am the parent. my child is %d\n", fork_rv);
    exit(0);
}

return 0;
}

fork产生子进程,父进程返回子进程pid,不为0,输出父进程,反之为子进程
745401-20151129165911641-651501902.png

六、forkdemo4

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

int main()
{
int fork_rv;

printf("Before: my pid is %d\n", getpid());

fork_rv = fork();       /* create new process   */

if ( fork_rv == -1 )        /* check for error  */
    perror("fork");

else if ( fork_rv == 0 ){ 
    printf("I am the child.  my pid=%d\n", getpid());
    printf("parent pid= %d, my pid=%d\n", getppid(), getpid());
    exit(0);
}

else{
    printf("I am the parent. my child is %d\n", fork_rv);
    sleep(10);
    exit(0);
}

return 0;
}

745401-20151129170032500-1858259190.png

七、forkgdb

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

int  gi=0;
int main()
{
int li=0;
static int si=0;
int i=0;

pid_t pid = fork();
if(pid == -1){
    exit(-1);
}
else if(pid == 0){
    for(i=0; i<5; i++){
        printf("child li:%d\n", li++);
        sleep(1);
        printf("child gi:%d\n", gi++);
        printf("child si:%d\n", si++);
    }
    exit(0);
    
}
else{
    for(i=0; i<5; i++){
        printf("parent li:%d\n", li++);
        printf("parent gi:%d\n", gi++);
        sleep(1);
        printf("parent si:%d\n", si++);
    }
exit(0);    

}
return 0;
}

父进程打印是先打印两句,然后休眠一秒,然后打印一句.子进程先打印一句,然后休眠一秒,然后打印两句。这两个线程是并发的,所以可以看到在一个线程休眠的那一秒,另一个线程在执行.
745401-20151129170416485-301081920.png

八、psh1

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

#define MAXARGS     20              
#define ARGLEN      100             

int execute( char *arglist[] )

execvp(arglist[0], arglist);        
perror("execvp failed");
exit(1);
}

char * makestring( char *buf )
{
char    *cp;

buf[strlen(buf)-1] = '\0';      
cp = malloc( strlen(buf)+1 );       
if ( cp == NULL ){          
    fprintf(stderr,"no memory\n");
    exit(1);
}
strcpy(cp, buf);        
return cp;          


int main()
{
char    *arglist[MAXARGS+1];        
int     numargs;            
char    argbuf[ARGLEN];         

numargs = 0;
while ( numargs < MAXARGS )
{                   
    printf("Arg[%d]? ", numargs);
    if ( fgets(argbuf, ARGLEN, stdin) && *argbuf != '\n' )
        arglist[numargs++] = makestring(argbuf);
    else
    {
        if ( numargs > 0 ){     
            arglist[numargs]=NULL;  
            execute( arglist ); 
            numargs = 0;        
        }
    }
}
return 0;
}

这个程序提示用户输入argv数组中的各个元素,以用户输入回车作为结束符,运行完指定的程序后,整个sh退出。同时只能运行一次命令中程序。
745401-20151129170838797-77554606.png

九、psh2

#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>
#include    <sys/types.h>
#include    <sys/wait.h>
#include    <unistd.h>
#include    <signal.h>

#define MAXARGS     20              
#define ARGLEN      100             

char *makestring( char *buf )
{
char    *cp;

buf[strlen(buf)-1] = '\0';      
cp = malloc( strlen(buf)+1 );       
if ( cp == NULL ){          
    fprintf(stderr,"no memory\n");
    exit(1);
}
strcpy(cp, buf);        
return cp;          
}

void execute( char *arglist[] )
{
int pid,exitstatus;             

pid = fork();                   
switch( pid ){
    case -1:    
        perror("fork failed");
        exit(1);
    case 0:
        execvp(arglist[0], arglist);        
        perror("execvp failed");
        exit(1);
    default:
        while( wait(&exitstatus) != pid )
            ;
        printf("child exited with status %d,%d\n",
                exitstatus>>8, exitstatus&0377);
}
}

int main()
{
char    *arglist[MAXARGS+1];        
int     numargs;            
char    argbuf[ARGLEN];         

numargs = 0;
while ( numargs < MAXARGS )
{                   
    printf("Arg[%d]? ", numargs);
    if ( fgets(argbuf, ARGLEN, stdin) && *argbuf != '\n' )
        arglist[numargs++] = makestring(argbuf);
    else
    {
        if ( numargs > 0 ){     
            arglist[numargs]=NULL;  
            execute( arglist ); 
            numargs = 0;        
        }
    }
}
return 0;
}

加入循环判断,不退出的话就会一直要你输入指令,并且对于子程序存在的状态条件。

745401-20151129171134750-1917002515.png

十、testbuf

#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("hello");
fflush(stdout);
while(1);
}

先输出hello,然后换行
745401-20151129171816172-88456941.png

testbuf3:将内容格式化输出到标准错误、输出流中。

#include <stdio.h>

int main()
{
fprintf(stdout, "1234", 5);
fprintf(stderr, "abcd", 4);
}

745401-20151129172217047-1398918617.png

十一、testpid

#include <stdio.h>
#include <unistd.h>

#include <sys/types.h>

int main()
{
printf("my pid: %d \n", getpid());
printf("my parent's pid: %d \n", getppid());
return 0;
}

分别输出父子的PID
745401-20151129172414907-1084284841.png

十二、testsystem

#include    <stdlib.h>

int main ( int argc, char *argv[] )
{

system(argv[1]);
system(argv[2]);
return EXIT_SUCCESS;
}  `

同时输出两条指令的结果。
745401-20151129172904828-1198318968.png

十三、waitdemo

#include    <stdio.h>
#include    <stdlib.h>
#include    <sys/types.h>
#include    <sys/wait.h>
#include    <unistd.h>

#define DELAY   10

void child_code(int delay)
{
printf("child %d here. will sleep for %d seconds\n", getpid(), delay);
sleep(delay);
printf("child done. about to exit\n");
exit(27);
}

void parent_code(int childpid)
{
int wait_rv;    
int child_status;
int high_8, low_7, bit_7;

wait_rv = wait(&child_status);
printf("done waiting for %d. Wait returned: %d\n", childpid, wait_rv);

high_8 = child_status >> 8;     /* 1111 1111 0000 0000 */
low_7  = child_status & 0x7F;   /* 0000 0000 0111 1111 */
bit_7  = child_status & 0x80;   /* 0000 0000 1000 0000 */
printf("status: exit=%d, sig=%d, core=%d\n", high_8, low_7, bit_7);
}

int main()
{
int  newpid;

printf("before: mypid is %d\n", getpid());

if ( (newpid = fork()) == -1 )
    perror("fork");
else if ( newpid == 0 )
    child_code(DELAY);
else
    parent_code(newpid);
}

745401-20151129173225282-917967818.png

十四、fifo 文件夹

FIFO严格遵循先进先出,对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>

#define FIFO_NAME "/tmp/myfifo"
#define BUFFER_SIZE PIPE_BUF


int main()
{
int pipe_fd;
int res;

int open_mode = O_RDONLY;
char buffer[BUFFER_SIZE + 1];
int bytes = 0;

memset(buffer, 0, sizeof(buffer));

printf("Process %d opeining FIFO O_RDONLY \n", getpid());
pipe_fd = open(FIFO_NAME, open_mode);
printf("Process %d result %d\n", getpid(), pipe_fd);

if (pipe_fd != -1) {
    do {
        res = read(pipe_fd, buffer, BUFFER_SIZE);
        bytes += res;
    } while (res > 0);
    close(pipe_fd);
} else {
    exit(EXIT_FAILURE);
}

printf("Process %d finished, %d bytes read\n", getpid(), bytes);
exit(EXIT_SUCCESS);
}

745401-20151129173831813-1942690679.png

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>

#define FIFO_NAME "/tmp/myfifo"
#define BUFFER_SIZE PIPE_BUF
#define TEN_MEG (1024 * 1024 * 10)

int main()
{
int pipe_fd;
int res;
int open_mode = O_WRONLY;

int bytes = 0;
char buffer[BUFFER_SIZE + 1];

if (access(FIFO_NAME, F_OK) == -1) {
    res = mkfifo(FIFO_NAME, 0777);
    if (res != 0) {
        fprintf(stderr, "Could not create fifo %s \n",
            FIFO_NAME);
        exit(EXIT_FAILURE);
    }
}

printf("Process %d opening FIFO O_WRONLY\n", getpid());
pipe_fd = open(FIFO_NAME, open_mode);
printf("Process %d result %d\n", getpid(), pipe_fd);

if (pipe_fd != -1) {
    while (bytes < TEN_MEG) {
        res = write(pipe_fd, buffer, BUFFER_SIZE);
        if (res == -1) {
            fprintf(stderr, "Write error on pipe\n");
            exit(EXIT_FAILURE);
        }
        bytes += res;
    }
    close(pipe_fd);
} else {
    exit(EXIT_FAILURE);
}

printf("Process %d finish\n", getpid());
exit(EXIT_SUCCESS);
}

745401-20151129174221719-1012549221.png

十五、env文件夹

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
printf("PATH=%s\n", getenv("PATH"));
setenv("PATH", "hello", 1);
printf("PATH=%s\n", getenv("PATH"));
#if 0
printf("PATH=%s\n", getenv("PATH"));
setenv("PATH", "hellohello", 0);
printf("PATH=%s\n", getenv("PATH"));


printf("MY_VER=%s\n", getenv("MY_VER"));
setenv("MY_VER", "1.1", 0);
printf("MY_VER=%s\n", getenv("MY_VER"));
#endif
return 0;
}

如果name在环境中不存在,那么很好办,在环境中添加这个新的变量就OK。
setenv函数必须在environment list中增加一个新的entry,然后动态申请存储空间来存储name=value,并且使entry指向该空间。

setenv函数不必在environment list中增加一个新的entry。当overwrite为0, 则不必改动entry的指向;当overwrite非0, 则直接使该entry指向name=value,当然该name=value也是存储在动态申请的内存里。

745401-20151129174803750-295958887.png

#include <stdio.h>
int main(void)
{
extern char **environ;
int i;
for(i = 0; environ[i] != NULL; i++)
    printf("%s\n", environ[i]);

return 0;
}

每个程序都有一个环境表,它是一个字符指针数组,其中每个指针包含一个以NULL结尾的C字符串的地址。全局变量environ则包含了该指针数组的地址
745401-20151129174950844-1062240887.png

十六、signal

#include    <stdio.h>
#include    <unistd.h>
#include    <signal.h>
#define INPUTLEN    100
void inthandler();  
int main()
{
struct sigaction newhandler;    
sigset_t blocked;   
char x[INPUTLEN];
newhandler.sa_handler = inthandler; 
newhandler.sa_flags = SA_RESTART|SA_NODEFER
    |SA_RESETHAND;  
sigemptyset(&blocked);  
sigaddset(&blocked, SIGQUIT);   
newhandler.sa_mask = blocked;   
if (sigaction(SIGINT, &newhandler, NULL) == -1)
    perror("sigaction");
else
    while (1) {
        fgets(x, INPUTLEN, stdin);
        printf("input: %s", x);
    }
return 0;
}
void inthandler(int s)
{
printf("Called with signal %d\n", s);
sleep(s * 4);
printf("done handling signal %d\n", s);
}

745401-20151129175514875-1438649354.png
signal函数,原型 signal(参数1,参数2);,其中参数1是我们进行处理的信号,参数2是我们处理的方式。

SIGNALDEMO1:捕捉信号

SIGNALDEMO2:忽略信号

SIGNALDEMO3:为处理信号做准备

十七、argv文件夹

745401-20151129180342516-586554588.png

十八、pipe文件夹

调用pipe来创建管道并将其两端连接到两个文件描述符,array[0]为读数据端的文件描述符,而array[1]则为写数据端的文件描述符,内部则隐藏在内核中,进程只能看到两个文件描述符。

745401-20151129180644125-1087148998.png

745401-20151129180733688-715748420.png

遇到的问题

运行testpp时出现段错误,发现可能出现了溢出状况,还是有一定不确定,需要再查阅书籍询问老师。

参考资料

教材:第八章,详细学习指导:http://group.cnblogs.com/topic/73069.html

课程资料:https://www.shiyanlou.com/courses/413 实验十,课程邀请码:W7FQKW4Y

教材中代码运行、思考一下,读代码的学习方法:http://www.cnblogs.com/rocedu/p/4837092.html

闫佳歆同学的博客:http://www.cnblogs.com/20135202yjx/p/5003653.html

《linux有名管道》(http://blog.csdn.net/firefoxbug/article/details/8137762

《进程间通信-命名管道FIFO》(http://blog.csdn.net/xiajun07061225/article/details/8471777

总结体会

本次实践运行了很多的代码,因为C语言的学习不够,所以导致看代码会有一定的吃力。很多时候都会选择通过运行结果去了解并加深对代码的理解,一种逆向学习。在今后的学习中,应更加踏实并不放过每一个细节,学到更多的知识。

转载于:https://www.cnblogs.com/20135323fuyunjin/p/5004579.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值