Linux实验报告
更新时间:2024-04-04 06:04:01 阅读量: 综合文库 文档下载
课程编号:B080103040
Linux操作系统 实验报告
姓 名 班 级 实验名称 邵春晓 软工1201 学 号 指 导 教 师 Linux操作系统实验 20124670 石 凯 开 设 学 期 实 验 时 间 2014-2015第一学期 第11周——第18周 评定人签字 评 定 日 期 石 凯 评 定 成 绩 东北大学软件学院
实验一 熟悉Linux环境
【实验内容】
一、练习常用的Shell命令。
当用户登录到字符界面系统或使用终端模拟窗口时,就是在和称为shell的命令解释程序进行通信。当用户在键盘上输入一条命令时,shell程序将对命令进行解释并完成相应的动作。这种动作可能是执行用户的应用程序,或者是调用一个编辑器、GNU/Linux实用程序或其他标准程序,或者是一条错误信息,告诉用户输入了错误的命令。 二、熟悉vim编辑器
在编写文本或计算机程序时,需要创建文件、插入新行、重新排列行、修改内容等,计算机文本编辑器就是用来完成这些工作的。
Vim编辑器的两种操作模式是命令模式和输入模式(如图2所示)。当vim处于命令模式时,可以输入vim命令。例如,可以删除文本并从vim中退出。在输入模式下,vim将把用户所输入的任何内容都当作文本信息,并将它们显示在屏幕上。 三、熟悉gcc编译器
GNU/Linux中通常使用的C编译器是GNU gcc。编译器把源程序编译生成目标代码的任务分为以下4步:
a. 预处理,把预处理命令扫描处理完毕 ;
b. 编译,把预处理后的结果编译成汇编或者目标模块;
c. 汇编,把编译出来的结果汇编成具体CPU上的目标代码模块; d. 连接,把多个目标代码模块连接生成一个大的目标模块; 四、熟悉gdb调试工具
LINUX包含了一个叫gdb的GNU调试程序。gdb是一个用来调试C和C++程序的强有力调试器。它使你能在程序运行时观察程序的内部结构和内存的使用情况。它具有以下一些功能: ·监视程序中变量的值;
·设置断点以使程序在指定的代码行上停止执行; ·一行行的执行代码。
五、掌握Linux下C程序编辑运行过程 Linux下编写C程序要经过以下几个步骤: ⑴启动常用的编辑器,键入C源程序代码。 ⑵编译源程序 ⑶运行可执行文件
【实验总结】
在学习linux的过程中间,最主要的就是耐心和细心。linux的命令很多,只有一遍一遍的看一次又一次的用,才能记住很多的命令,才能很好的使用linux。通过这次实验,我对linux的系统以及vim编辑器,gcc编译器,gdb调试工具更加熟悉,这也让我让我能够更加努力学习。
实验二 文件操作
【实验内容】
1.文件的创建(必做题)
编写程序,实现cp命令的功能。被复制的文件名与复制出的新文件由用户指定。调用方法:“你编写的程序名 被复制文件名 复制出的文件名”。要求程序有一定的健壮性,即对用户错误调用及其他错误要有处理和反馈。(提示:可以使用man手册查看具体的系统调用,e.g., man 2 open)。 #include
main(int ac, char *av[]){ int fd1, fd2; int n;
char buf[512];
if(ac!=3){
printf(\ exit(1); }
if((fd1=open(av[1], O_RDONLY))==-1){ perror(\ exit(1); }
if((fd2=creat(av[2], 0777))==-1){ perror(\ exit(1); }
while((n=read(fd1, buf, 512))>0){ write(fd2, buf, n); }
close(fd1); close(fd2); }
2.查看目录内容及文件属性 (1)编写程序,实现ls -l的功能。调用方法:“你编写的程序名”——这时打印出当前目录文件及其属性;“你编写的程序名 目录名”——这时在终端显示给定目录下的文件及其属性。(提示:当用户给定目录后,需要改变进程的当前目录,可使用chdir()。) #include
void mode_to_str(mode_t mode, char *str){ strcpy(str, \
if(S_ISDIR(mode)) str[0]='d';
if(mode & 0400) str[1]='r'; if(mode & 0200) str[2]='w'; if(mode & 0100) str[3]='x';
if(mode & 040) str[4]='r'; if(mode & 020) str[5]='w'; if(mode & 010) str[6]='x';
if(mode & 04) str[7]='r'; if(mode & 02) str[8]='w'; if(mode & 01) str[9]='x'; }
void show_file_info(char * filename){ struct stat buf; char modestr[10]; stat(filename, &buf);
mode_to_str(buf.st_mode, modestr);
printf(\ printf(\
printf(\ printf(\ printf(\
printf(\ printf(\}
main(int ac, char *av[]){ DIR * dirp;
struct dirent * p;
if(1==ac){
dirp=opendir(\ }else{
dirp=opendir(av[1]); }
while((p=readdir(dirp))!=NULL){ if(p->d_name[0]!='.'){
show_file_info(p->d_name); } }
closedir(dirp); }
3. 设备文件操作
在/dev目录下,找到你的鼠标对应的文件。打开这个文件,从该文件循环读出字符,并将字符对应的ascII代码在终端显示出来。
⑷ 该程序段中每个进程退出时都用了语句exit(0),为什么?
答:每个进程退出时都用了语句exit(0),一方面要结束进程,另外向父进程返回结束标志0。 2.修改上面的程序,增加语句signal(SIGINT,SIG_IGN)和语句signal(SIGQUIT,SIG_IGN),再观察程序执行时屏幕上出现的现象,并分析其原因。 # include
void IntDelete() {
kill(pid1,10); kill(pid2,12); EndFlag=1; }
void Int1() {
printf(“child process 1 is killed by parent !\\n”); exit(0); }
void Int2() {
printf(“child process 2 is killed by parent !\\n”); exit(0); }
main() {
int exitcode;
signal(SIGINT,SIG_IGN); signal(SIGQUIT,SIG_IGN); while((pid1=fork())==-1); if(pid1==0)
{
signal(SIGUSR1,Int1); signal(SIGINT,SIG_IGN); pause(); exit(0);
} else {
while((pid2=fork())= =-1);
if(pid2==0) {
signal(SIGUSR2,Int2); signal(SIGINT,SIG_IGN); pause(); exit(0);
} else {
signal(SIGINT,IntDelete);
waitpid(-1,&exitcode,0); /*等待任何子进程中断或结束*/ printf(“parent process is killed \\n”); exit(0);
}
} }
运行程序并分析结果。 答:
结果分析:由于忽略了中断与退出信号,程序会一直保持阻塞状态而无法退出。
⑶司机售票员问题(选做题)
编程用fork()创建一个子进程代表售票员,司机在父进程中,再用系统调用signal()让父进程(司机)捕捉来自子进程(售票员)发出的中断信号,让子进程(售票员)捕捉来自(司机)发出的中断信号,以实现进程间的同步运行。
创建子进程代表售票员,父进程代表司机,同步过程如下:
售货员捕捉SIGINT(代表开车),发SIGUSR1给司机,司机打印:let us go go go 售票员捕捉SIFQUIT(代表开车),发SIGUSR2给司机,司机:top the bus
司机捕捉SIGTSTP(代表车到总站),发SIGUSR1给售票员,售票员打印:please get off the bus
#include
puts(\ }
void Init2() {
puts(\ }
void Init3() {
puts(\ }
void Init4() {
kill(pid1,10); }
void Init5() {
int k=getppid(); kill(k,10); }
void Init6() {
int j=getppid(); kill(j,12); }
int main(void) {
signal(SIGINT,SIG_IGN); signal(SIGQUIT,SIG_IGN); signal(SIGTSTP,SIG_IGN); pid1=fork();
if(pid1>0)//父进程 {
signal(10,Init1); signal(12,Init2);
signal(SIGTSTP,Init4); while(1); exit(0); }
else if(pid1==0) {
signal(SIGINT,Init5); signal(SIGQUIT,Init6); signal(10,Init3); while(1); exit(0); } else {
puts(\
}
return EXIT_SUCCESS; }
【实验总结】
通过这次实验,我了解了信号的概念,知道了:每个进程在运行时,都要通过信号机制来检查是否有信号到达。若有,便中断正在执行的程序,转向与该信号相对应的处理程序,以完成对该事件的处理;处理结束后再返回到原来的断点继续执行。
(三)进程的管道通信实验
【实验内容】
1.编制一段程序,实现进程的管道通信。使用pipe()建立一条管道线。两个子进程p1和p2分别向管道各写一句话:
Child 1 is sending message! Child 2 is sending message!
而父进程则从管道中读出来自于两个子进程的信息,显示在屏幕上。 <参考程序>
# include
int fd[2];
char OutPipe[100],InPipe[100]; pipe(fd);
while((pid1=fork())= = -1); if(pid1= =0)
{
lockf(fd[1],1,0); sprintf(OutPipe,“child 1 process is sending message!”);
write(fd[1],OutPipe,50); sleep(5);
lockf(fd[1],0,0); exit(0);
} else {
while((pid2=fork())= = -1); if(pid2= =0)
{
lockf(fd[1],1,0); sprintf(OutPipe,“child 2 process is sending message!”);
write(fd[1],OutPipe,50); sleep(5);
lockf(fd[1],0,0);
exit(0); } else
{
wait(0);
read(fd[0],InPipe,50);
printf(“%s\\n”,InPipe);
wait(0);
read(fd[0],InPipe,50); printf(“%s\\n”,InPipe); exit(0); } } }
实验结果为:
延迟5秒后显示:
child1 process is sending message!
再延迟5秒:
child2 process is sending message!
2.在父进程中用pipe()建立一条管道线,往管道里写一句话,两个子进程接收这句话。 答:实验程序如下:
#include
int n, fd[2]; pid_t pid, pid1;
char buffer[BUFSIZ+1]; if(pipe(fd) < 0) {
printf(\ exit(1); }
if((pid = fork()) < 0) {
printf(\ exit(1); }
else if(pid > 0) {
if((pid1 = fork()) < 0) {
printf(\ exit(1); }
else if(pid1 >0) {
close(fd[0]);
write(fd[1], \ }
else {
close(fd[1]);
n = read(fd[0], buffer, 6);
write(STDOUT_FILENO,\ write(STDOUT_FILENO, buffer, n); } } else {
close(fd[1]);
n = read(fd[0], buffer, 6);
write(STDOUT_FILENO,\ write(STDOUT_FILENO, buffer, n); }
exit(0); }
【实验总结】
通过这次实验,了解什么是管道,知道了管道是UNIX系统的一大特色。所谓管道,是指能够连接一个写进程和一个读进程的、并允许它们以生产者—消费者方式进行通信的一个共享文件,又称为pipe文件。
(四)消息的发送与接收实验
【实验内容】
1.消息的创建、发送和接收。使用系统调用msgget( ),msgsnd( ),msgrev( ),及msgctl( )编制一长度为1k的消息发送和接收的程序。
<参考程序> ①client.c
#include
char mtext[1000]; }msg;
int msgqid;
void client() {
int i;
msgqid=msgget(MSGKEY,0777); /*打开75#消息队列*/ for(i=10;i>=1;i--) {
msg.mtype=i;
printf(“(client)sent\\n”);
msgsnd(msgqid,&msg,1024,0); /*发送消息*/ }
exit(0); }
main( ) {
client( ); }
②server.c
#include
char mtext[1000]; }msg;
int msgqid;
void server( ) {
msgqid=msgget(MSGKEY,0777|IPC_CREAT); /*创建75#消息队列*/ do {
msgrcv(msgqid,&msg,1030,0,0); /*接收消息*/
printf(“(server)received\\n”);
}while(msg.mtype!=1);
msgctl(msgqid,IPC_RMID,0); /*删除消息队列,归还资源*/ exit(0); }
main( ) {
server( ); }
程序说明:
①为了便于操作和观察结果,编制二个程序client.c和server.c,分别用于消息的发送与接收。 ②server建立一个 Key 为75的消息队列,等待其它进程发来的消息。当遇到类型为1的消息,则作为结束信号,取消该队列,并退出server。server每接收到一个消息后显示一句“(server)received。”
③client使用 key为75的消息队列,先后发送类型从10到1的消息,然后退出。最后一个消息,即是 server端需要的结束信号。client 每发送一条消息后显示一句 “(client)sent”。 ④注意: 二个程序分别编辑、编译为client与server。 执行: 实验截图:
2. 在父进程中创建一个消息队列,用fork创建一个子进程,在子进程中将一条消息传送至消息队列,父进程接受队列的消息,并将消息送屏幕显示。
编写程序如下:
#include
struct msg_st //消息队列的结构体 {
int my_msg_type;
char msg_text[BUFSIZ]; };
int main(int argc,char **argv) {
pid_t pid; int i = 1; int status;
if( (pid = fork()) == -1) {
perror(\ exit(EXIT_FAILURE); }
else if ( pid == 0) //子进程 {
struct msg_st some_data; int msgid;
char buffer[BUFSIZ];
if((msgid = msgget((key_t)12345,0666|IPC_CREAT)) == -1 ) {
perror(\ exit(EXIT_FAILURE); }
printf(\ fgets(buffer,BUFSIZ,stdin); some_data.my_msg_type = 1;
strcpy(some_data.msg_text,buffer);
if((msgsnd(msgid,(void *) &some_data,MAX_TEXT,0)) == -1) {
perror(\ exit(EXIT_FAILURE); } return 0; }
else //父进程 {
int msgid1;
struct msg_st some_data1; int msg_to_recevie = 0;
if((msgid1= msgget((key_t)12345,0666|IPC_CREAT)) == -1) {
perror(\ exit(EXIT_FAILURE); }
if(msgrcv(msgid1,(void *) &
some_data1,BUFSIZ,msg_to_recevie , 0) == -1) {
perror(\ exit(EXIT_FAILURE); }
printf(\ if(msgctl(msgid1,IPC_RMID,0) == -1) {
fprintf(stderr,\
exit(EXIT_FAILURE); }
return 0; } }
【实验总结】
通过这次实验,了解了消息的概念,即消息(message)是一个格式化的可变长的信息单元。消息机制允许由一个进程给其它任意的进程发送一个消息。当一个进程收到多个消息时,可将它们排成一个消息队列;熟悉了消息传送机理;学习了消息的发送与接收。
实验四 编写Web服务器
【实验内容】
1.服务器设计重点
基于socket的客户/服务器系统大多是类似的。一旦理解了一个socket流的客户/服务器系统,就可以理解大多数其他的系统。 2.三个主要操作
客户和服务器都是进程。服务器设立服务,然后进入循环接收和处理请求。客户连接到服务器,然后发送、接受或者交换数据,最后退出。该交互过程中主要包含了一下三个操作: (1)服务器设立服务 (2)客户连接到服务器 (3)服务器和客户处理事务
客户: 服务器:
建立服务 连接到服务器 接收请求 获取服务 提供服务 挂断连接 挂断连接
3.连接过程
操作1:建立服务器端socket
设立一个服务一般需要如下3个步骤: (1)创建一个 socket
socket = socket ( PF_INET, SOCK_STREAM, 0 ) (2)给 socket 绑定一个地址 bind ( sock, &addr, sizeof(addr) ) (3)监听接入请求 listen ( sock, queue_size )
步骤1:
创建一个服务器端socket
为了避免在编写服务器时重复输入上述代码,将这3个步骤组合成一个函数:make_server_socket。在编写服务器的时候,只需调用该函数就可以创建一个服务端socket。具体如下:
sock=make_server_socket(int portnum)
return -1 if error, or a server socket listening at port ―portnum‖
操作2:建立到服务器的连接
基于流的网络客户连接到服务器包含以下两个步骤: (1)创建一个 socket
socket = socket ( PF_INET, SOCK_STREAM, 0 ) (2)使用该 socket 连接到服务器
connect ( sock, &serv_addr, sizeof ( serv_addr ) )
步骤2:
创建并连接客户socket到服务器
将这两个步骤抽象成一个函数:connet_to_server。当编写客户端程序时,只要调用该函数就可以建立到服务器的连接。具体如下: fd=connet_to_server(hostname, portnum) return -1 if error,
or a fd open for reading and writing connected to the socket at port ―portnum‖ on host ―hostname‖ /*
* socklib.c *
* This file contains functions used lots when writing internet * client/server programs. The two main functions here are: *
* make_server_socket( portnum ) returns a server socket * or -1 if error
* make_server_socket_q(portnum,backlog) *
* connect_to_server(char *hostname, int portnum) * returns a connected socket * or -1 if error */
socklib.c
#include
#define HOSTLEN 256 #define BACKLOG 1
int make_server_socket_q(int , int );
int make_server_socket(int portnum) { return make_server_socket_q(portnum, BACKLOG); }
int make_server_socket_q(int portnum, int backlog) { struct sockaddr_in saddr; /* build our address here */ struct hostent *hp; /* this is part of our */ char hostname[HOSTLEN]; /* address */ int sock_id; /* the socket */ sock_id = socket(PF_INET, SOCK_STREAM, 0); /* get a socket */ if ( sock_id == -1 ) return -1; /** build address and bind it to socket **/ bzero((void *)&saddr, sizeof(saddr)); /* clear out struct */ gethostname(hostname, HOSTLEN); /* where am I ? */ hp = gethostbyname(hostname); /* get info about host */ /* fill in host part */ bcopy( (void *)hp->h_addr, (void *)&saddr.sin_addr, hp->h_length); saddr.sin_port = htons(portnum); /* fill in socket port */ saddr.sin_family = AF_INET ; /* fill in addr family */ if ( bind(sock_id, (struct sockaddr *)&saddr, sizeof(saddr)) != 0 ) return -1; /** arrange for incoming calls **/ if ( listen(sock_id, backlog) != 0 ) return -1; return sock_id; }
int connect_to_server(char *host, int portnum) { int sock; struct sockaddr_in servadd; /* the number to call */ struct hostent *hp; /* used to get number */
}
/** Step 1: Get a socket **/
sock = socket( AF_INET, SOCK_STREAM, 0 ); /* get a line */ if ( sock == -1 ) return -1; /** Step 2: connect to server **/
bzero( &servadd, sizeof(servadd) ); /* zero the address */ hp = gethostbyname( host ); /* lookup host's ip # */ if (hp == NULL) return -1;
bcopy(hp->h_addr, (struct sockaddr *)&servadd.sin_addr, hp->h_length); servadd.sin_port = htons(portnum); /* fill in port number */ servadd.sin_family = AF_INET ; /* fill in socket type */ if ( connect(sock,(struct sockaddr *)&servadd, sizeof(servadd)) !=0) return -1; return sock;
操作3:客户/服务器的会话
至此,可以使用专门的函数来建立服务器端,也有专门的函数来连接到服务器。 (1)一般的客户端
网络客户通常调用服务器来获得服务,一个典型的客户程序如下: mian(){ int fd; fd=connect_to_server(host, port); /*call the server*/ if(fd==-1) exit(1); /*or die*/ talk_with_server(fd); /*chat with server*/ close(fd); /*hang up when done*/ }
函数talk_with_server 处理与服务器的对话。具体的内容取决于特定应用。例如,e-mail客户和邮件服务器交谈的是邮件,而天气预报客户和服务器交谈的则是天气。 (2)一般的服务器端 一个典型的服务器如下: main(){ int sock, fd; /*socket and connection*/ if(sock==-1) exit(1); while(1){ fd=accept(sock, NULL, NULL); /*take next call*/
else if ( strcmp(extension, \ content = \ else if ( strcmp(extension, \ content = \ else if ( strcmp(extension, \ content = \ fpsock = fdopen(fd, \ fpfile = fopen( f , \ if ( fpsock != NULL && fpfile != NULL ) { header( fpsock, content ); fprintf(fpsock, \ while( (c = getc(fpfile) ) != EOF ) putc(c, fpsock); fclose(fpfile); fclose(fpsock); } exit(0); }
运行Web服务器:
编译程序,并在某个端口(建议用80)运行它: $cc webserv.c socklib.c –o webserv $./webserv 80 编译成功:
现在可以访问Web服务器,网址为http://yourhostname/。将html文件放到该目录中并用http://yourhostname/filename.html来打开它。创建下面的shell脚本: #!/bin/sh
printf ―Content-type: text/plain\\n\\nhello\\n‖;
将它命名为hello.cgi,用chmod改变权限为755,然后用浏览器调用该程序:http://yourhostname/hello.cgi。
用chmod改变权限为755:
四、实验总结
通过做该实验,我学到了很多课本上没有的知识,增强了自己的动手能力和编程能力。时在课本上看了很多的程序,但是我很少编写过,对书上的程序仅仅有一些浅显的理解。经过做实验,我对程序有了更深一层的理解,更加形象生动的感知到了每个符号的生命和活力。不但了解了并发服务器的运行模式和套接字的作用和使用方法,而且加深了对课本知识的理解。并且掌握了socket编程,以及调试技巧。由于Web服务器要使用多进程(或多线程),让我对进程有了更深入的理解。
正在阅读:
Linux实验报告04-04
中国人民解放军越野车四大金刚 - 图文04-07
市政工程安全教育试题211-14
谁是你的守护天使07-27
2010 年度《复印报刊资料》转载学术论文指数排名学术专题来源期刊名单08-29
2013高一上册政治期末试卷06-02
浅析铁路工程桥梁桥墩技术措施01-24
语文S版五年级下册复习资料(完整)05-06
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 实验
- 报告
- Linux
- 上海天天快递杨浦区分店员工流失现状分析与对策研究
- 基层武装部调研报告篇1
- 小学五年级数学下册《长方体和正方体》拔高训练题
- 四年级下册综合实践活动教案B
- 首届测绘地理信息教学成果奖获奖项目 - 图文
- 与食品经营相适应的主要设备设施布局和操作流程文件
- 制剂工程学试题库
- 全国2012年10月高等教育自学考试
- 基于51单片机的花样流水灯设计 - 毕业论文 - 图文
- 水泥土墙计算计算书
- 上海交大生命科学导论复习大纲 - 图文
- PBS管理系统--torque
- 中国毛绒玩具行业市场调研报告
- 四线制改变运行方向电路
- 2017年中考文言文阅读真题汇编 带答案解析
- 全国监狱名录
- 智能控制技术复习题课后答案 - 图文
- 电炉硅锰合金生产成本构成分析
- 信用评级要素分析法
- 一瞬间的感悟作文