本文首发链接
查看我的个人博客: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. 什么是线程?什么是进程?编程中采用多进程或者多线程技术,各有什么优缺点?
进程
是系统中独立存在的实体,它可以拥有自己独立的资源。在没有经过进程本身允许的情况下,其他进程不能访问到这些资源。这一点上和线程有很大的不同。线程
是轻量级进程,是共享资源的程序实体,创建一个线程所花费的系统开销要比创建一个进程小的多。- 多进程和多线程优缺点:
多线程的优点
:无需跨进程边界; 程序逻辑和控制方式简单; 所有线程可以直接共享内存和变量等; 线程方式消耗的总资源比进程方式好。多线程缺点
:每个线程与主程序共用地址空间,受限于2GB地址空间; 线程之间的同步和加锁控制比较麻烦; 一个线程的崩溃可能影响到整个程序的稳定性; 到达一定的线程数程度后,即使再增加CPU也无法提高性能; 线程能够提高的总性能有限。多进程优点
:每个进程互相独立,不影响主程序的稳定性; 通过增加CPU,就可以容易扩充性能; 可以尽量减少线程加锁/解锁的影响,极大提高性能; 每个子进程都有2GB地址空间和相关资源,总体能够达到的性能上限大。多进程缺点
:逻辑控制复杂,需要和主程序交互; 需要跨进程边界,如果有大数据量传送,就不太好,适合小数据量传送、密集运算;调度开销比较大。
4. 什么是进程?Linux系统中进程间通信机制有哪些?请列举出至少四种Linux进程通讯机制。
进程
是系统中独立存在的实体,它可以拥有自己独立的资源。在没有经过进程本身允许的情况下,其他进程不能访问到这些资源。这一点上和线程有很大的不同。- Linux系统中进程间通信机制有:
管道
先进先出
信号量
消息队列
套接字
5. 什么是线程?什么是进程?进程间通信与线程间通讯各有什么优缺点?
进程
是系统中独立存在的实体,它可以拥有自己独立的资源。在没有经过进程本身允许的情况下,其他进程不能访问到这些资源。这一点上和线程有很大的不同。线程
是轻量级进程,是共享资源的程序实体,创建一个线程所花费的系统开销要比创建一个进程小的多。- 进程间通信与线程间通讯优缺点:
- 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;
}