2019-04-26 19:21:53 liudaka 阅读数 239
  • 玩转Linux:常用命令实例指南

    本课程以简洁易懂的语言手把手教你系统掌握日常所需的Linux知识,每个知识点都会配合案例实战让你融汇贯通 。课程通俗易懂,简洁流畅,适合0基础以及对Linux掌握不熟练的人学习; 注意: 1、本课程原价99元,现在仅需29元!购课就送5门价值300元的编程课! 2、购课后登陆csdn学院官网,在课程目录页面即可下载课件。 学完即可轻松应对工作中 85% 以上的 Linux 使用场景 【限时福利】 1)购课后按提示添加小助手,进答疑群,还可获得价值300元的编程大礼包! 2)本课程【现在享受秒杀价39元】 3)本月购买此套餐加入老师答疑交流群,可参加老师的免费分享活动,学习最新技术项目经验。 注意: 1)现在购买至少享受60元优惠; 2)购课后添加微信eduxy-1,发送订单截图领取300元编程礼包。 --------------------------------------------------------------- 这门课程,绝对不会让你觉得亏! 29元=掌握Linux必修知识+社群答疑+讲师社群分享会+300元编程礼包。   人工智能、物联网、大数据时代,Linux正有着一统天下的趋势,几乎每个程序员岗位,都要求掌握Linux。本课程零基础也能轻松入门。   在这门课中,我们保证你能收获到这些 1)快速掌握 Linux 常用命令及配置 2)Linux核心知识点 3) 文件、进程、磁盘、用户管理,以及网络工具命令、文件传输等 4)Vi/Vim编辑器用法  

    7154 人正在学习 去看看 良许

【实验题目】

linux程序设计实验

【实验目的与要求】

  1. Linux常用命令
  2. Linux下的shell命令
  3. Linux下的c编程
  4. Linux API编程

【实验原理】

  1. Linux常用命令
  2. Linux下的shell命令
  3. Linux下的c编程
  4. Linux API编程

【实验内容】

  1. 给出下面的shell脚本,对该shell脚本中的内容逐行分析并执行查看结果。
  2. 输入文件名,判断在当前目录下是否存在该文件,若存在则输出相关信息。
  3. 判断当前用户是否和输入的用户名一致
  4. 输入两个数,比较它们的大小,并输出相应的结果。
  5. 在文本文件myfile中查找单词“GNU”,并输出相应信息。
  6. 获得系统时间,并判断是上午、下午还是晚上。
  7. 根据不同的菜单选择,分别显示当前时间、登录用户和当前工作目录。
  8. 从若干数中寻找最小值。
  9. 在当前目录下逐个显示.sh结尾的shell脚本的内容。
  10. 计算当前目录下可执行文件的个数。
  11. 显示命令行参数。
  12. 逐个打印当前目录下的文件。
  13. 计算1到100的和。

14.显示2-100之间的所有素数。

15.显示1-100之间的整数

16.将输入的文件名存入文件filenames,直至输入no。

17.测试文件是否为目录

18.使用函数判断一个数是否是素数

19.运用函数判断两个数的大小关系。

20:shell 脚本实现三个数大小排序

21:输入分数值,100则显示满分,90-99显示优秀,80-89显示良好,70-79显示中等,60-69显示及格,低于60显示不及格。

22:用shell脚本语言实现一个斐波那契数列的前10项和

【程序代码与实验结果】

  1. 给出下面的shell脚本,对该shell脚本中的内容逐行分析并执行查看结果。
  2. 输入文件名,判断在当前目录下是否存在该文件,若存在则输出相关信息。
  3. 判断当前用户是否和输入的用户名一致
  4. 输入两个数,比较它们的大小,并输出相应的结果。
  5. 在文本文件myfile中查找单词“GNU”,并输出相应信息。
  6. 获得系统时间,并判断是上午、下午还是晚上。
  7. 根据同的菜单选择,分别显示当前时间、登录用户和当前工作目录。
  8. 从若干数中寻找最小值。
  9. 在当前目录下逐个显示.sh结尾的shell脚本的内容。
  10. 计算当前目录下可执行文件的个数。
  11. 显示命令行参数。
  12. 逐个打印当前目录下的文件。
  13. 计算1到100的和。

14.显示2-100之间的所有素数。

15.显示1-100之间的整数

16.将输入的文件名存入文件filenames,直至输入no。

17.测试文件是否为目录

18.使用函数判断一个数是否是素数

19.运用函数判断两个数的大小关系。

20:shell 脚本实现三个数大小排序

21:输入分数值,100则显示满分,90-99显示优秀,80-89显示良好,70-79显示中等,60-69显示及格,低于60显示不及格。

22:用shell脚本语言实现一个斐波那契数列的前10项和

2019-07-11 00:07:37 weixin_38102771 阅读数 173
  • 玩转Linux:常用命令实例指南

    本课程以简洁易懂的语言手把手教你系统掌握日常所需的Linux知识,每个知识点都会配合案例实战让你融汇贯通 。课程通俗易懂,简洁流畅,适合0基础以及对Linux掌握不熟练的人学习; 注意: 1、本课程原价99元,现在仅需29元!购课就送5门价值300元的编程课! 2、购课后登陆csdn学院官网,在课程目录页面即可下载课件。 学完即可轻松应对工作中 85% 以上的 Linux 使用场景 【限时福利】 1)购课后按提示添加小助手,进答疑群,还可获得价值300元的编程大礼包! 2)本课程【现在享受秒杀价39元】 3)本月购买此套餐加入老师答疑交流群,可参加老师的免费分享活动,学习最新技术项目经验。 注意: 1)现在购买至少享受60元优惠; 2)购课后添加微信eduxy-1,发送订单截图领取300元编程礼包。 --------------------------------------------------------------- 这门课程,绝对不会让你觉得亏! 29元=掌握Linux必修知识+社群答疑+讲师社群分享会+300元编程礼包。   人工智能、物联网、大数据时代,Linux正有着一统天下的趋势,几乎每个程序员岗位,都要求掌握Linux。本课程零基础也能轻松入门。   在这门课中,我们保证你能收获到这些 1)快速掌握 Linux 常用命令及配置 2)Linux核心知识点 3) 文件、进程、磁盘、用户管理,以及网络工具命令、文件传输等 4)Vi/Vim编辑器用法  

    7154 人正在学习 去看看 良许

一. 前言

        在之前的博客介绍了一个简单 Linux 服务器程序的实现,光有服务器没有客户端是无法判断服务器的功能是否可用的,本文我们就写一个简单的客户端程序,可以与服务器进行简单的交互。

 

二. 简单Linux客户端程序

1. TCP客户端程序实现流程

        之前的 TCP 服务器程序是监听 8080 端口,只要客户端发送数据过去就往客户端回复 "Hello World",如果想要与服务器建立连接并通信:我们需要创建一个 socket 套接字,调用 connect 与服务器建立起连接,之后再通过 read,write 进行数据读写交互,流程如下图。

 

2. TCP客户端程序的代码实现

#include <stdio.h>                                                                                                                  
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <arpa/inet.h>
#include <strings.h>
#include <string.h>
#include <ctype.h>

#define SERVER_ADDR     "127.0.0.1"
#define SERVER_PORT     8080

int main()
{
    int cfd = 0;
    struct sockaddr_in saddr;
    char buf[BUFSIZ] = {0};
    int i = 0,n = 0;

    cfd = socket(AF_INET,SOCK_STREAM,0);

    bzero(&saddr,sizeof(saddr));
    saddr.sin_family = AF_INET;
    inet_pton(AF_INET,SERVER_ADDR,&saddr.sin_addr.s_addr);
    saddr.sin_port = htons(SERVER_PORT);

    connect(cfd,(struct sockaddr*)&saddr,sizeof(saddr));
    printf("已经成功发起了连接!\n");

    while(1)
    {   
        fgets(buf,sizeof(buf),stdin);
        if(strncmp(buf,"quit",4) == 0)
        {   
            break;
        }   
        write(cfd,buf,strlen(buf));
        memset(buf,0,sizeof(buf));
        n = read(cfd,buf,sizeof(buf));
        for(i=0;i<n;++i)                                                                                                            
        {   
            buf[i] = toupper(buf[i]);
        }   
        printf("%s",buf);
        memset(buf,0,sizeof(buf));
    }

    close(cfd);

    return 0;
}

 程序讲解

1. 首先调用一个 socket 函数创建一个套接字,第一个参数 AF_INET 代表是 IPv4 地址,第二个参数 SOCK_STREAM 代表流式协议,第三个参数 0 代表默认协议,这里是 TCP。(因为服务器是 TCP 通信的,所以我们使用的是 SOCK_STREAM )

2. 创建好套接字后,我们需要指定好要连接的服务器 IP 和端口(IP + Port 标识网络中的一个进程,这些信息存放在一个struct sockaddr_in 类型的结构体中,然后将该结构体传入给 connect 函数调用即可,struct  sockaddr_in 的类型结构如下。

struct sockaddr_in {
    short            sin_family;   // e.g. AF_INET
    unsigned short   sin_port;     // e.g. htons(3490)
    struct in_addr   sin_addr;     // see struct in_addr, below
    char             sin_zero[8];  // zero this if you want to
};
struct in_addr {
    unsigned long s_addr;  // load with inet_aton()
};

sin_family:指定地址类型,AF_INET 代表 IPv4,AF_INET6 代表 IPv6。

sin_port:指定服务器的端口号,需要使用网络字节序,所以参数要使用 htons 函数将本机字节序转换为网络字节序。

sin_addr:其实是一个 unsigned long 的 32 位整数,我们需要使用 inet_pton 或者 inet_aton 将点分十进制的 IP 地址转化为一个 unsigned long 类型的整数。

sin_zero:置为 0 即可。

初始化 struct sockaddr_in 类型的结构体变量之后,我们就可以调用 connect 函数与服务器建立连接了。

connect 函数原型:int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

第一个参数传入使用 socket 函数创建套接字返回的句柄,第二个参数类型是 const struct sockaddr *,所以我们需要将 &saddr 的地址类型做一个强制转换,第三个参数指定 saddr 的大小即可。

关于上述一些 API 的具体含义将会在后续文章做深入讲解,这里只需要先简单了解含义即可。

3. 打印出 "已经成功发起了连接后",程序进入一个 while(1) 死循环中,每次我们从终端输入字符串后,客户端就调用 write 将该字符串发送给服务器,然后调用 read 等待服务器回复信息。服务器收到字符串后,就往客户端回复 "Hello World",此时客户端收到了 "Hello World",就将 "Hello World" 转换为全部大写的,最后再次等待终端输入字符串。

 

3. UDP客户端程序的代码实现

         因为暂时没有讲解 UDP 服务器的实现,后续再补充这部分的内容。

 

三. 结束

         这里的客户端程序实现是比较粗糙的,没有进行过多的程序返回值判断,例如 connect 调用失败就不该让流程往下走,而且 write,read 并不能保证一定调用成功。之后我们会具体讲解 socket,connect,listen,accept 等函数,到那时候我们再让我们的客户端程序更加完善。

 

2011-09-26 10:39:49 Natepan 阅读数 3067
  • 玩转Linux:常用命令实例指南

    本课程以简洁易懂的语言手把手教你系统掌握日常所需的Linux知识,每个知识点都会配合案例实战让你融汇贯通 。课程通俗易懂,简洁流畅,适合0基础以及对Linux掌握不熟练的人学习; 注意: 1、本课程原价99元,现在仅需29元!购课就送5门价值300元的编程课! 2、购课后登陆csdn学院官网,在课程目录页面即可下载课件。 学完即可轻松应对工作中 85% 以上的 Linux 使用场景 【限时福利】 1)购课后按提示添加小助手,进答疑群,还可获得价值300元的编程大礼包! 2)本课程【现在享受秒杀价39元】 3)本月购买此套餐加入老师答疑交流群,可参加老师的免费分享活动,学习最新技术项目经验。 注意: 1)现在购买至少享受60元优惠; 2)购课后添加微信eduxy-1,发送订单截图领取300元编程礼包。 --------------------------------------------------------------- 这门课程,绝对不会让你觉得亏! 29元=掌握Linux必修知识+社群答疑+讲师社群分享会+300元编程礼包。   人工智能、物联网、大数据时代,Linux正有着一统天下的趋势,几乎每个程序员岗位,都要求掌握Linux。本课程零基础也能轻松入门。   在这门课中,我们保证你能收获到这些 1)快速掌握 Linux 常用命令及配置 2)Linux核心知识点 3) 文件、进程、磁盘、用户管理,以及网络工具命令、文件传输等 4)Vi/Vim编辑器用法  

    7154 人正在学习 去看看 良许

本文只是总结一下linux下tcp与udp程序的编写,其实不管平台如何,简单的tcp与udp程序的结构还是不会变的。如下所示:



tcp(基于链接)的简单程序结构

udp(无连接)的程序结构

过程不在赘述,看看一个基于上面过程的简单udp代码:

udpserver.c

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>


#define PORT 8900


int main()
{

	int sockfd;
	struct sockaddr_in server;
	struct sockaddr_in client;
	char send_buf[2048];
	char recv_buf[2048];
	int length;
	int sendnum;
	int recvnum;
	int port;


	port = PORT;
	int opt = SO_REUSEADDR;
	


/*The first stage:initnial phase*/

/*1.1 generating socket  phrahse*/

	if (-1==(sockfd=socket(AF_INET,SOCK_DGRAM,0)))
	{
		perror("error in generate socket\n");
		exit(1);

	}

	#ifdef DEBUG
		printf("the sokcet id is %d\n",sockfd);
		printf("enter binding phrase....\n");
	#endif
	setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));

/*1.2 binding the socket*/

	memset(&server,0,sizeof(struct sockaddr));
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = htonl(INADDR_ANY);
	server.sin_port = htons(port);

	if (-1==bind(sockfd,(struct sockaddr*)&server,sizeof(struct sockaddr)))
	{
		perror("error in binding phrase\n");
		close(sockfd);
		exit(1);

	}


	#ifdef DEBUG
		printf("leaving binding phrase\n");
		printf("entering data exchange phrase\n");
	#endif

	length = sizeof(struct sockaddr_in); 

/* The Second Stage: data exchange phrase */
	while(1)
	{
		memset(&send_buf,0,sizeof(send_buf));
		memset(&recv_buf,0,sizeof(recv_buf));
        
  		/* receive the data from the client*/

		recvnum=recvfrom(sockfd,recv_buf,sizeof(recv_buf),0,(struct sockaddr*)&client,&length);
	
		recv_buf[recvnum]='\0';
		printf("the message from the client is %s:\n",recv_buf);
	

		sendnum = sprintf(send_buf,"hello,the guest from %s",inet_ntoa(client.sin_addr));
		sendto(sockfd,send_buf,sendnum,0,(struct sockaddr*)&client,sizeof(struct sockaddr));

		if (0==strcmp(recv_buf,"quit"))
		{
			perror("the server is terminted by client\n");
			close(sockfd);
			return 0;
			
			
		}

	}

	
	
}


udpclient.c

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>


void print_usage(char* str)
{
	printf("the command %s usage is:\n",str);
	printf("%s Ip_Address [port] \n");

}




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

	int sockfd;
	struct sockaddr_in server;
	struct sockaddr_in reply;
	char send_buf[2048];
	char recv_buf[2048];
	int length;
	int sendnum;
	int recvnum;
	int port;

	port =	atoi(argv[2]);


	if ((2>argc) ||(argc>3))
	{
		print_usage(argv[0]);
		exit(1);


	}

/*The first stage:initnial phase*/

/*1.1 generating socket  phrahse*/

	if (-1==(sockfd=socket(AF_INET,SOCK_DGRAM,0)))
	{
		perror("error in generate socket\n");
		exit(1);

	}

	#ifdef DEBUG
		printf("the sokcet id is %d\n",sockfd);
		printf("enter data exchange  phrase....\n");
	#endif

/*1.2 setting the destinate address */

	memset(&server,0,sizeof(struct sockaddr));
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = inet_addr(argv[1]);
	server.sin_port = htons(port);


/* The Second Stage: data exchange phrase */
	
	memset(&send_buf,0,sizeof(send_buf));
	memset(&recv_buf,0,sizeof(recv_buf));

	printf("what words do you want to tell to server:\n");
	gets(send_buf);
	
        
  	/* send  the data to the server*/
	
	sendnum = strlen(send_buf);
	if(0>sendto(sockfd,send_buf,sendnum,0,(struct sockaddr*)&server,sizeof(struct sockaddr)))
	{
		perror("send data error\n");
		close(sockfd);
		exit(0);
	}
	
	recvnum = recvfrom(sockfd,recv_buf,sizeof(recv_buf),0,(struct sockaddr *)&server,&length);
	
	if (0>recvnum)
	{
		
		perror("receive data error\n");
		close(sockfd);
		exit(0);
	}	

	recv_buf[recvnum]='\0';
	printf("the message from the server is :%s\n",recv_buf);

	close(sockfd);
	exit(0);
}

以上即完成了简单的udp程序。另一个tcp程序在此处下载。同样比较简单,不解释!

在文章后面说一下大小端(big endian于little endian)的问题吧,相信大家都知道大小端到底使什么东西,这里也不多说,现在要提到的是如何如何编程实现判断所用机器是大端机器还是小端机器。我们知道,在C语言中,union中的字段是“共享内存”的,在一个union结构中,它的大小取决于其字段中最大的那个并且与之相等。其实想到这儿相信大家都已经知道了怎么来判断机器的大小端了,没错,就是使用union类型的特点进行判断。现在就基于C中的union写一个判断机器是大小端的程序。如下:

#include<stdio.h>

union Nate
{
	unsigned short s;
	char cs[2];
}nate;

void main()
{
	nate.s = 1;
	printf("nate.s is : %x\n",nate.s);
	printf("nate.cs[0] is : %d\n",nate.cs[0]);
	printf("nate.cs[1] is : %d\n",nate.cs[1]);
	if(nate.cs[0] == 1)
	{
		printf("little endian!\n");
	}
	else if(nate.cs[0] == 0)
	{
		printf("big endian!\n");
	}
}

在gcc中编译运行程序即可看到本机器是大端还是小端了!这可以说是使用C中union的特性的一个好的应用,对于理解C中union类型也不错!

文中包含程序在此处可以下载:http://download.csdn.net/detail/Natepan/3636259



2017-12-11 09:40:24 dezhihuang 阅读数 3470
  • 玩转Linux:常用命令实例指南

    本课程以简洁易懂的语言手把手教你系统掌握日常所需的Linux知识,每个知识点都会配合案例实战让你融汇贯通 。课程通俗易懂,简洁流畅,适合0基础以及对Linux掌握不熟练的人学习; 注意: 1、本课程原价99元,现在仅需29元!购课就送5门价值300元的编程课! 2、购课后登陆csdn学院官网,在课程目录页面即可下载课件。 学完即可轻松应对工作中 85% 以上的 Linux 使用场景 【限时福利】 1)购课后按提示添加小助手,进答疑群,还可获得价值300元的编程大礼包! 2)本课程【现在享受秒杀价39元】 3)本月购买此套餐加入老师答疑交流群,可参加老师的免费分享活动,学习最新技术项目经验。 注意: 1)现在购买至少享受60元优惠; 2)购课后添加微信eduxy-1,发送订单截图领取300元编程礼包。 --------------------------------------------------------------- 这门课程,绝对不会让你觉得亏! 29元=掌握Linux必修知识+社群答疑+讲师社群分享会+300元编程礼包。   人工智能、物联网、大数据时代,Linux正有着一统天下的趋势,几乎每个程序员岗位,都要求掌握Linux。本课程零基础也能轻松入门。   在这门课中,我们保证你能收获到这些 1)快速掌握 Linux 常用命令及配置 2)Linux核心知识点 3) 文件、进程、磁盘、用户管理,以及网络工具命令、文件传输等 4)Vi/Vim编辑器用法  

    7154 人正在学习 去看看 良许

通过程序名获得进程号,然后和当前程序进程号做对比。


int isRunning()
{
    int ret = 0;
    char sCurrPid[16] = {0};
    sprintf(sCurrPid, "%d\n", getpid());
    
    FILE *fstream=NULL;    
    char buff[1024] = {0};  

    // a.out为你的可执行程序名
    if(NULL==(fstream=popen("ps -aux | grep a.out | grep -v grep | awk '{print $2}'", "r")))    
    {   
        fprintf(stderr,"execute command failed: %s", strerror(errno));    
        return -1;    
    }   
    while(NULL!=fgets(buff, sizeof(buff), fstream)) {
        if (strlen(buff) > 0) {
            if (strcmp(buff, sCurrPid) !=0) {
                printf("%s, %s\n", buff, sCurrPid); 
                ret = 1;
                break;
            }
        }
    }
    pclose(fstream);
    
    return ret;
}


另外一种兼容嵌入式设备。因为嵌入式设备可能没有awk命令,因此采用下面这个通用的方法。

char* getPidFromStr(const char *str)
{
    static char sPID[8] = {0};
    int tmp = 0;
    int pos1 = 0;
    int pos2 = 0;
    int i = 0;
    int j = 0;

    for (i=0; i<strlen(str); i++) {
        if ( (tmp==0) && (str[i]>='0' && str[i]<='9') ) {
            tmp = 1;
            pos1 = i;
        }
        if ( (tmp==1) && (str[i]<'0' || str[i]>'9') ) {
            pos2 = i;
            break;
        }
    }
    for (j=0,i=pos1; i<pos2; i++,j++) {
        sPID[j] = str[i];
    }
    return sPID;
}


int isRunning()
{
    int ret = 0;
    char sCurrPid[16] = {0};
    sprintf(sCurrPid, "%d", getpid());
    
    FILE *fstream=NULL;    
    char buff[1024] = {0};   
    if(NULL==(fstream=popen("ps -e -o pid,comm | grep a.out | grep -v PID | grep -v grep", "r")))    
    {   
        fprintf(stderr,"execute command failed: %s", strerror(errno));    
        return -1;    
    }   
    while(NULL!=fgets(buff, sizeof(buff), fstream)) {
        char *oldPID = getPidFromStr(buff);
        if ( strcmp(sCurrPid, oldPID) != 0 ) {
            printf("程序已经运行,PID=%s\n", oldPID);
            ret = 1;
        }
    }
    pclose(fstream);
    
    return ret;
}


2017-01-02 10:03:02 hubinqiang 阅读数 1206
  • 玩转Linux:常用命令实例指南

    本课程以简洁易懂的语言手把手教你系统掌握日常所需的Linux知识,每个知识点都会配合案例实战让你融汇贯通 。课程通俗易懂,简洁流畅,适合0基础以及对Linux掌握不熟练的人学习; 注意: 1、本课程原价99元,现在仅需29元!购课就送5门价值300元的编程课! 2、购课后登陆csdn学院官网,在课程目录页面即可下载课件。 学完即可轻松应对工作中 85% 以上的 Linux 使用场景 【限时福利】 1)购课后按提示添加小助手,进答疑群,还可获得价值300元的编程大礼包! 2)本课程【现在享受秒杀价39元】 3)本月购买此套餐加入老师答疑交流群,可参加老师的免费分享活动,学习最新技术项目经验。 注意: 1)现在购买至少享受60元优惠; 2)购课后添加微信eduxy-1,发送订单截图领取300元编程礼包。 --------------------------------------------------------------- 这门课程,绝对不会让你觉得亏! 29元=掌握Linux必修知识+社群答疑+讲师社群分享会+300元编程礼包。   人工智能、物联网、大数据时代,Linux正有着一统天下的趋势,几乎每个程序员岗位,都要求掌握Linux。本课程零基础也能轻松入门。   在这门课中,我们保证你能收获到这些 1)快速掌握 Linux 常用命令及配置 2)Linux核心知识点 3) 文件、进程、磁盘、用户管理,以及网络工具命令、文件传输等 4)Vi/Vim编辑器用法  

    7154 人正在学习 去看看 良许

本文首发链接
查看我的个人博客: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;
}

linux 条件判断

阅读数 493

linux shell 程序设计

阅读数 743

没有更多推荐了,返回首页