Linux程序设计复习

本文首发链接
查看我的个人博客:https://hubinqiang.com

福建师范大学软件学院Linux程序设计复习


一、简答题

1. Linux系统中有几种I/O模型?请简要说明各个I/O模型的特点。

五种IO的模型:

  • 阻塞I/O:最常用、最简单、效率最低,表现为进程放弃CPU,让给其他进程使用CPU。

  • 非阻塞I/O:可防止进程阻塞在I/O操作上,即设置I/O相关的系统调用为non-blocking,随后进行的I/O操作无论有没有可用数据都会立即返回。

  • 多路复用I/O:同时对各个I/O进行控制,让阻塞发生在我们的多路复用I/O操作的系统调用上面,而不是真正去执行I/O的系统调用。

  • 信号驱动I/O(异步非阻塞IO):一种异步通信模型,利用信号机制,安装信号SIG IO的处理函数,通过监控文件描述符,当其就绪时,通知目标进程进行I/O操作。

  • 异步I/O:调用aio_read函数,告诉内核描述字,缓冲区指针,缓冲区大小,文件偏移以及通知的方式,然后立即返回。当内核将数据拷贝到缓冲区后,再通知应用程序。

2. 在Linux Socket 编程中,服务器模型有循环服务器和并发服务器两种模型,请简要说明这两种服务器模型的特点。

  • 循环服务器:服务器在同一个时刻只可以响应一个客户端的请求
  • 并发服务器:服务器在同一个时刻可以响应多个客户端的请求

3. 什么是线程?什么是进程?编程中采用多进程或者多线程技术,各有什么优缺点?

  1. 进程是系统中独立存在的实体,它可以拥有自己独立的资源。在没有经过进程本身允许的情况下,其他进程不能访问到这些资源。这一点上和线程有很大的不同。
  2. 线程是轻量级进程,是共享资源的程序实体,创建一个线程所花费的系统开销要比创建一个进程小的多。
  3. 多进程和多线程优缺点:
    • 多线程的优点:无需跨进程边界; 程序逻辑和控制方式简单; 所有线程可以直接共享内存和变量等; 线程方式消耗的总资源比进程方式好。
    • 多线程缺点:每个线程与主程序共用地址空间,受限于2GB地址空间; 线程之间的同步和加锁控制比较麻烦; 一个线程的崩溃可能影响到整个程序的稳定性; 到达一定的线程数程度后,即使再增加CPU也无法提高性能; 线程能够提高的总性能有限。
    • 多进程优点:每个进程互相独立,不影响主程序的稳定性; 通过增加CPU,就可以容易扩充性能; 可以尽量减少线程加锁/解锁的影响,极大提高性能; 每个子进程都有2GB地址空间和相关资源,总体能够达到的性能上限大。
    • 多进程缺点:逻辑控制复杂,需要和主程序交互; 需要跨进程边界,如果有大数据量传送,就不太好,适合小数据量传送、密集运算;调度开销比较大。

4. 什么是进程?Linux系统中进程间通信机制有哪些?请列举出至少四种Linux进程通讯机制。

  1. 进程是系统中独立存在的实体,它可以拥有自己独立的资源。在没有经过进程本身允许的情况下,其他进程不能访问到这些资源。这一点上和线程有很大的不同。
  2. Linux系统中进程间通信机制有:
    • 管道
    • 先进先出
    • 信号量
    • 消息队列
    • 套接字

5. 什么是线程?什么是进程?进程间通信与线程间通讯各有什么优缺点?

  1. 进程是系统中独立存在的实体,它可以拥有自己独立的资源。在没有经过进程本身允许的情况下,其他进程不能访问到这些资源。这一点上和线程有很大的不同。
  2. 线程是轻量级进程,是共享资源的程序实体,创建一个线程所花费的系统开销要比创建一个进程小的多。
  3. 进程间通信与线程间通讯优缺点:
    • linux中的进程,是有fork()系统调用创建的,进程间都有独立的地址空间,他们之间不能直接通信,必须通过一些IPC进程进程间通信机制来完成。常见的IPC有:PIPE,命名管道,信号,共享内存以及socket等;
    • linux中的线程,是clone()系统调用创建的,一个进程下的线程间是共享内存空间的,故线程A可以之间访问线程B中定义的变量,但是必须注意并发的情况。“线程上下文”的规模要远远小于“进程上下文”。

二、Shell编程

1. 编写程序计算前n个自然数之和,要求n的值由用户输入。

#!/bin/bash

read -p "请输入n:" n

if [ $n>=0 ] 
then
    s=0
    for((i=1;$i<=n;i++))
    do
        s=$(($s+$i))
    done
    echo "n的和为:"$s
fi

2. 编写一个程序判断 /tmp/file1 这个文件是不是一个目录文件。

#!/bin/bash

filename="/tmp"

if [ -d $filename ]
then
    echo $filename"是目录文件"
else
    echo $filename"不是目录文件"
fi

3. 编写一个程序判断某个用户是否登陆了系统。(被判断的用户要求不能在程序中写死。可以从命令行参数指定)

#!/bin/bash

read -p "请输入用户名:" USER

user='who | awk {print $1}'

for i in $user
do
    if [ $i == "$USER" ]
    then
        echo "已登录"
    else
        echo "未登录"
    fi
done

4. 编写一个程序查找某个用户登录时所使用的shell程序。(提示:在 /etc/passwd 文件包含了本机所有用户的信息。每一行的信息的具体为:用户名:密码:用户ID:组ID:用户全名:主目录:登录shell)

#!/bin/bash

read -p "请输入用户:" user

if grep -q $user /etc/passwd
then
    grep $user /etc/passwd | awk 'BEGIN{FS=":"}{print $7}'
fi

5. 假设在/tmp目录中有stu1,stu2,stu3,…,stu50五十个文件,请编写一个程序,用来删除50个文件。(假设用户具有操作权限)

#!/bin/bash

for((i=1;$i < 50;i++))
do
    rm "stu"$i
done

6. 编写程序,统计/etc目录下的文件数和目录数个数。

#!/bin/bash
f=0
d=0
for i in /etc/*
do
    if [ -d $i ]
    then
        d=$(($d+1))
    elif [ -f $i ]
    then
        f=$(($f+1))
    fi
done
echo "d:"$d
echo "f:"$f    

7. 编写一个程序,测试并输出某个指定文件是不是一个目录以及目录拥有者。

#!/bin/bash

read -p "请输入:" File

if [ -d $File ]
then
    ls -d -l $File | awk '{print "文件的拥有者:"$3}'
else
    echo "这不是目录文件"
fi

三、C编程

1. mkdir命令接受-p选项,可以在需要时创建上层目录,请编写一个支持这个选项的命令版本。(请画出该程序的流程图)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
int main(int argc, char* argv[]) {
    if (argc != 2 && argc != 3) {
        printf("must use <name> <path> or <name> <path> -p");
        exit(-1);
    }
    char paths[100][100];
    char *path = argv[1];
    int root = 0;
    if ('/' == path[0]) {
        root = 1;
    }
    char *delim = "/";
    char *p;
    int i = 0;
    strcpy(paths[i], strtok(path, delim));
    while((p = strtok(NULL, delim))) {
        i++;
        strcpy(paths[i], p);
    }
    i++;
    if (i > 1 && argc < 3) {
        printf("please use -p");
        exit(-1);
    }
    if (i > 1 && strcmp(argv[2],"-p") != 0) {
        printf("please use -p");
        exit(-1);
    }
    char s[500] = {};
    if (root == 1) {
        strcat(s,"/");
    }
    for (int j = 0; j < i; j++){
        strcat(s, paths[j]);
        mkdir(s, 0777);
        strcat(s, "/" );
    }
    exit(0);
}

2. 请编写一个程序实现ls命令的功能,该程序必须满足下面两个要求:

1)能显示文件名就可以。2)设置一个递归显示的选项。当用户输入该选项时候,能把指定目录下的子目录内容也显示出来。

#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc,char *argv[]){
    if (argc != 2 && argc !=3) {
        printf("need at least two params\n");
        return 0;
     }
    if(argc==3){
        if(strcmp(argv[1],"-r")==0)
            dols(argv[2],1);
    }
    else
        dols(argv[1],0);
}
int dols(char* dirname,int r){
     DIR *dp ; //create a DIR pointer
     struct dirent *dirp;
     if ((dp = opendir(dirname)) == NULL) {
         return 0;
     }
     while ((dirp = readdir(dp)) != NULL) {
         if(strcmp(dirp->d_name,"..")!=0 && strcmp(dirp->d_name,".")!=0){
             printf("%s\n",dirp->d_name);
             if(r){
                 char *path[2];
                 char split[]={'/'};
                 int len=strlen(dirname);
                 char *parent=(char*)malloc(len+1);
                 strcpy(parent,dirname);
                 path[0]="ls";
                 path[1]= strcat(parent,strcat(dirp->d_name,split));
                 dols(path[1],1);
             }
         }
     }
     closedir(dp);
     return 0;
}

3. 请编写一个程序实现cp命令功能。该程序必须满足下面两个要求:

1)能复制文件。2)能复制目录。

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc,char *argv[]){
    if(argc!=3){
        printf("need three params\n");
        return 0;
    }else if(access(argv[1],0)!=0){
       printf("file or dir not exists\n");
    }else if(opendir(argv[1])==NULL){
        FILE *from,*to;
        from=fopen(argv[1],"r");
        to=fopen(argv[2],"w");
        char ch;
        while((ch=fgetc(from))!=EOF){
            fputc(ch,to);
        }
        fclose(from);
        fclose(to);
        printf("file %s is created\n",argv[2]);
    }else{
        if(access(argv[2],0)!=0){
            mkdir(argv[2],0755);
        }
        chdir(argv[2]);
        if(mkdir(argv[1],0755)==0)
            printf("dir %s is copied\n",argv[1]);
        else
            printf("copy failed");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/hubinqiang/article/details/53975981