资源描述
一、填空题
1、 linux中,对串口参数进行配置的数据结构名是 __termios____。
2、 gcc的编译流程分为4个步骤:预处理、 __编译____、汇编、 __链接____。
3、 获取当前进程ID的方法是 __getpid()____。
4、 对文件的打开操作有open与fopen,它们哪个是标准库函数 __fopen()____它的返回值是 __指向FILE的指针____。
5、 一个由c语言占用的内存分为代码区与数据区,数据区又可以分为 __静态数据区____与动态数据区,动态数据区分为堆、 __栈____。
6、 linux的管道通信可以分为匿名管道、 ___有名管道___与 __标准管道____。
7、 linux中的网络编程是通过套接字接口来进行的,常见的套接字有三种类型: ___流式套接字___、 __数据报套接字____与 __原始套接字____。
8、 在linux中,用户空间的进程可以直接通过 ___系统调用___来获取操作系统内核提供的服务。
9、 linux中,对串口进行操作的函数中,激活串口配置的函数是 __tcsetattr()____。
10、 linux中使用较多的进程间通信方式包括管道、信号、信号量、 ___消息队列___、 __共享内存____。
11、 makefile规则是make进行处理的依据,它包括了 __依赖文件____、 ___目标体___及其之间的命令语句。
12、 互斥锁与信号量为linux中的线程同步机制,其中 ___信号量___适合于同时可用的资源为多个的情况。
13、 系统调用分为进程控制、进程间通信、文件系统管理、系统管理、存储管理、网络管理、socket管理、用户管理等。
14、 终端分为3种模式规范模式、非规范模式与原始模式
二、选择题
1. 下面关于linux下串口操作正确的描述是【 C 】
A.串口的奇偶校验必须使能 B.不能通过linux api设置串口的停止位
C. 串口配置好后,其读写操作与普通文件就是一样的了
D.串口文件可以通过lseek改变读写指针
2. 下列关于makefile说法错误的是【 B 】
A.创建目标体的命令必须以制表符开头 B. makefile变量名可以包含“#”字符串
C. makefile变量对大小写敏感 D. “-C dir”表示读入指定目录dir下的makefile
3. 下列关于linux多线程编程不正确的是【 D 】
A. 不同进程的线程间不能用信号量来同步;
B. pthread线程库符合POSIX接口;
C. 必须包含头文件pthread.h;
D. phtread_join( )作用是将参数中的指定线程挂起;
4. 下列关于linux网络编程不正确的说法是【 C 】
A. send()既可用在tcp中,也可用在udp中;
B. sendto()既可用在tcp中,也可用在udp中;
C. 不管是客户端还是服务器端必须调用bind;
D. 每一个socket都用一个半相关描述{本地地址、本地端口}
5. 从文件描述符fd中读出200个字节到首地址为buff的缓冲区的正确底层IO操作是【 B 】
A. read(buff,200,fd); B. read(fd,buff,200);
C. read(fd,200,buff); D. read(200,buff,fd);
6. 使用下面哪条命令可以查询目标文件所依赖的动态链接库。【 B 】
A. nm; B. readelf;
C. ld; D. objcopy
7. 下面关于linux进程控制不正确的描述的是【 A 】
A. wait( )调用一定会使得父进程阻塞
B. exit()会清理IO缓冲,而_exit()不会清理IO缓冲
C. 在执行execl函数后,原调用进程的内容除了进程号外,其他全部被新的进程替换了
D. fork( )的返回值在父子进程中是不一样的
8. 将max.c生成动态链接库的正确命令是。【 B 】
A. gcc –c max.c
B. gcc -fpic –shared –o libmax.so max.c
C. gcc –o libmax.so max.c
D. gcc –static –o libmax.so max.c
9. 下面关于linux进程通信正确的是【 C 】
A. 信号量是进程间通信机制中唯一同步机制
B. 消息队列读取函数msgrcv()只能读取队头的消息
C. 共享内存的实现分为两个步骤:创建或打开共享内存与映射共享内存
D. 信号量既可以解决进程间的同步问题,但不能解决进程间的互斥问题。
10. linux网络编程中,下面哪个函数是客户端、服务端所必须调用的。【 C 】
A. listen( )
B. accept( )
C. socket( )
D. bind( )
11.使用下面哪个函数返回值可知道文件操作已到文件末尾【C】
A.fopen B.ftell C.feof D.fseek
三、判断题
1. select主要解决了多路IO复用的问题。(√ )
2. 嵌入式linux的底层IO函数(如read())带有缓冲区,可直接对文件进行读写操作。( X) 不带缓冲区
3. 嵌入式linux的标准IO函数(如fread())不带有缓冲区,可直接对文件进行读写操作。( X) 不可直接对文件操作
4. linux api是linux操作系统直接提供的函数接口。(X ) 不是直接
5. 参数“-static”的作用是告诉gcc及库进行静态链接。(√ )
6. internet上的数据在网络上是以高位字节优先的顺序在网络上传输的。( √)
7. 创建线程的实质就是确定该线程函数的入口点,通常使用的函数是pcreate_thread。( X) pthread_create
8. 当linux线程出现错误的时候,可以使用exit( )终止线程。(X ) pthread_exit
9. fork( )函数是linux中一个非常重要的函数,在子进程中其返回值等于0。( √)
10. linux中不是所有的socket都要调用bind函数进行端口绑定。(√ )
11. 标准IO函数fread读取成功时返回的是成功读取的记录数。(X ) 记录数的数目
12. 底层IO函数read读取成功返回的的时成功读取字节数(√)
13. 在linux中,每个api都会对应一个或多个系统调用(X) 可以不对应
14. Internet上的数据在网络上是以低位字节优先的顺序在网络上传输的(X) 高位字节
15. select主要解决了多路IO复用的问题(√) poll也是
16. linux中socket一定要调用bind函数进行端口绑定(X) TCP要,UDP不用
17. 参数“-static”的作用是告诉gcc及库进行静态链接(√) “-shared”动态链接
18. fork()函数是linux中一个非常重要的函数,如果成功,父进程中其返回值大于1(√) 子进程返回0,父进程返回子进程的进程号
19. 参数“-fpic”的作用是告诉gcc生产及位置相关的目标代码(X) 无关
20. 普通可实现进程间的全双工通信(X) 半双工
四、 简答题
1. 画图说明linux系统下用TCP协议网络编程时客户端与服务器的步骤。
2. 画图说明linux系统下用UDP协议网络编程时客户端与服务器的步骤。
3. 简述linux系统调用、API及系统命令之间的关系。
系统调用是指操作系统提供给用户程序调用的一组“特殊”接口,用户程序可以通过这组“特殊”接口来获得操作系统内核提供的服务。而实际使用过程中,我们通常调用的用户编程接口就是API;系统命令相对API更高了一层,它实际上一个是可执行程序,它的内部引用了用户编程接口(API)来实现相应的功能。他们的关系:
4. #简述在linux下实现进程通信的几种方式的各自特点?
匿名管道: 具有亲缘关系的进程间,半双工,数据在内存中
有名管道: 可用于任意进程间,双工,有文件名,数据在内存
信号: 唯一的异步通信方式
消息队列:常用于cs模式中, 按消息类型访问 ,可有优先级,无须同步机制。
共享内存:效率最高(直接访问内存) ,需要同步、互斥机制
信号量:用于解决进程间的同步及互斥问题的一种进程间通信机制
5. #共享内存是如何实现进程通信的?它是用什么方法(函数):创建、映射、撤销映射、删除?。
创建/打开共享内存. ftok(),shmget()
映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问. shmat()
撤销共享内存映射. shmdt()
删除共享内存对象. shmctl()
6. #创建守护进程的过程:
①调用fork创建子进程。
父进程终止,让子进程在后台继续执行。
②子进程调用setsid产生新会话期并失去控制终端
调用setsid()使子进程成为新会话组长与新的进程组长,同时失去控制终端
③改变当前工作目录为根目录chdir()
一般将工作目录改变到根目录,这样进程的启动目录也可以被卸掉。
④重设文件创建掩码umask()
清除从父进程那里继承来的文件创建掩码,设为0。
⑤关闭打开的文件描述符close()
⑥用openlog函数建立及syslogd的连接
五、编程题
1、请使用open、read、write、lseek、fork、pipe、sleep与waitpid
等函数实现如下功能:
1) 子进程把src.txt文件末尾的5个字符读出来;
2) 再通过管道发送给父进程;
3) 父进程收到后将它们输出到显示终端。
注意:请自行定义运行过程中的提示信息,头文件可省略!
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define src "src.txt"
int main()
int src_file,pipe_fd[2];
pid_t pid;
unsigned char buff[5],buff1[10];
int real_read;
src_file=open(src,O_RDONLY);
if(src_file<0)
printf("open src failed!\n");
exit(1);
if(pipe(pipe_fd)<0)
printf("Pipe creat failed!\n");
exit(1);
memset(buff,0,sizeof(buff));
memset(buff1,0,sizeof(buff1));
pid=fork();
if(pid==0)
close(pipe_fd[0]);
sleep(3);
lseek(src_file,-6,SEEK_END);
real_read=read(src_file,buff,5);
write(pipe_fd[1],buff,real_read);
close(pipe_fd[1]);
exit(0);
else
close(pipe_fd[1]);
sleep(1);
wait();
read(pipe_fd[0],buff1,sizeof(buff1));
printf("Receive data from son:%s\n",buff1);
close(pipe_fd[0]);
close(src_file);
exit(0);
2、用tcp协议实现(只须编写服务器程序)
服务器端首先建立起socket,然后及本地端口进行绑定,接着就开始接收从客户端的连接请求并建立及它的连接,接下来,接收客户端发送的消息并显示出来,当收到“exit”时退出。
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#define PORT 4321
#define BUFFER_SIZE 1024
#define MAX_QUE_CONN_NM 5
int main()
struct sockaddr_in server_sockaddr,client_sockaddr;
int sin_size,recvbytes;
int sockfd, client_fd;
char buf[BUFFER_SIZE];
/*建立socket连接*/
if ((sockfd = socket(AF_INET,SOCK_STREAM,0))== -1)
perror("socket");
exit(1);
printf("Socket id = %d\n",sockfd);
/*设置sockaddr_in 结构体中相关参数*/
server_sockaddr.sin_family = AF_INET;
server_sockaddr.sin_port = htons(PORT);
server_sockaddr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_sockaddr.sin_zero), 8);
int i = 1;/* 允许重复使用本地地址及套接字进行绑定 */
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
/*绑定函数bind()*/
if (bind(sockfd, (struct sockaddr *)&server_sockaddr,
sizeof(struct sockaddr)) == -1)
perror("bind");
exit(1);
printf("Bind success!\n");
/*调用listen()函数,创建未处理请求的队列*/
if (listen(sockfd, MAX_QUE_CONN_NM) == -1)
perror("listen");
exit(1);
printf("Listening....\n");
sin_size=sizeof(struct struct sockaddr) ;
/*调用accept()函数,等待客户端的连接,并创建一个新的socket为本次连接服务*/
if ((client_fd = accept(sockfd,
(struct sockaddr *)&client_sockaddr, &sin_size)) == -1)
perror("accept");
exit(1);
/*调用recv()函数接收客户端的请求*/
memset(buf , 0, sizeof(buf));
if ((recvbytes = recv(client_fd, buf, BUFFER_SIZE, 0)) == -1)
perror("recv");
exit(1);
printf("Received a message: %s\n", buf);
close(sockfd);
exit(0);
2、用UDP协议实现(只须编写服务器端程序):
服务器端首先建立起socket,然后及本机IP与端口进行绑定,接着可循环接收客户端发送的消息并显示出来,当收到“exit”时退出。
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include<stdlib.h>
int main(void)
int sockfd;
struct sockaddr_in server,client;
int port = 1234;
int opt = SO_REUSEADDR;
int rt;
int addrlen;
//char sendbuf[100];
char rbuf[100];
int num;
sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd==-1)
perror("socket");
exit(1);
//避免出现地址已经使用的错误
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
bzero(&server,sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY; //回送地址,指本地机,一般用来测试使用
server.sin_port = htons(port);
rt=bind(sockfd, (struct sockaddr *)& server, sizeof(server));
if (rt== -1)
perror("bind");
exit(1);
addrlen=sizeof(client);
while(1)
{ //接收客户端信息
num=recvfrom(sockfd,rbuf,sizeof(rbuf),0,(struct sockaddr *)&client,&addrlen);
if(num<0)
perror("recvfrom");
break;
rbuf[num]='\0';
//显示客户端信息,如果客户端发来exit则退出循环
printf("%s:%d %s\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port),rbuf);
if(strcmp(rbuf,"exit")==0)
break;
close(sockfd);
3、利用信号量实现:
主线程负责从键盘获取两个整数,子线程1负责对这两个整数完成求与运算并把结果打印出来,子线程2负责对这两个整数完成乘法运算并打印出来。三个线程要求遵循如下同步顺序:
a) 主线程获取两个数;
b) 子线程1计算;
c) 子线程2计算;
d) 转到a。
#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <stdlib.h>
sem_t can_add;//能够进行加法计算的信号量
sem_t can_multiply;
sem_t can_scanf;//能够进行键盘输入数的信号量
double x,y;
void *thread_add(void *arg)//加法线程入口函数
while(1)
sem_wait(&can_add);//申请信号量
printf("x+y=%.3lf\n",x+y);
sem_post(&can_multiply);//释放信号量
void *thread_multiply(void *arg)//乘法线程入口函数
while(1)
sem_wait(&can_multiply);
printf("x*y=%.3lf\n",x*y);
sem_post(&can_scanf);
int main()
pthread_t tid1,tid2;
sem_init(&can_add,0,0);//初始化can_add信号量
sem_init(&can_multiply,0,0);
sem_init(&can_scanf,0,1);//初始化can_scanf信号量
if(pthread_create(&tid1,NULL,thread_add,NULL)<0)
printf("Create thread_add failed!\n");
exit(0);
if(pthread_create(&tid2,NULL,thread_multiply,NULL)<0)
printf("Create thread_multiply failed!\n");
exit(0);
while(1)
sem_wait(&can_scanf);//申请信号量
printf("Please input two numbers:");
scanf("%lf%lf",&x,&y);
if(x==0&&y==0)
pthread_cancel(tid1);
pthread_cancel(tid2);
break;
sem_post(&can_add);//释放信号量
exit(0);
第 18 页
展开阅读全文