Linux课程设计报告(linux程序设计课程设计)

http://www.itjxue.com  2023-02-25 07:35  来源:未知  点击次数: 

课程设计报告要写哪几步,各有什么要求?

、设计过程(方案论证及用EWB模拟分析)。

2、理论分析(公式计算,数据分析)。

3、将理论值与实际值比较,分析误差。

4、电路稳定后测完数据、验收电路板并上交。

以上为电子类课程设计报告内容。

嵌入式linux课程设计

Ⅰ 跪求 ARM嵌入式linux系统开发详解(珍藏版)pdf

珍藏版啊。。

Ⅱ 学嵌入式linux需要先学什么

刚入门的时候,淘宝买一块cortex m3开发板即可入手,通过项目,你需要了解:任务调度、进程间通信、内存管理、设备驱动、文件系统、TCP/IP协议栈、同步异步、中断、软件架构插件化等等基本原理,这些对你后面转Linux应用开发,安卓开发,后台开发大有好处。

到这一步,就看自己职业方向想往哪里发展,如果是想深入IOT物联网做端云连接,那么可以把几种基本总线驱动,I2C、SPI、USART理解透,如果是想拥抱互联网转入应用开发,那么可以把基础组件,如协议栈、文件系统吃透,BAT面试不是很难,问的都是这些基础。

顺便说一下,学东西就要学对市场有用的,不要过于学习屠龙之术,炫技给个人带来不了财富,公司需要的是能干活的人。

不准备讲过于偏硬件的知识如Cortex-M3的多种中断模式,操作寄存器组,芯片降噪等内容,而是专注于操作系统基本知识和项目经验,这些对于开发者后面接触Linux系统大有脾益,这些软件开发经验也是去互联网公司看重的能力。如有需要学习Linux命令请如下查找:

Ⅲ 基于linux嵌入式平台井字棋课程设计

基于linux嵌入式平台井字棋课程

这么肯定还好的

Ⅳ 跪求一份完整的嵌入式Linux方面的C项目实例

怎样的人适合学习嵌入式?

学习嵌入式需要有一定的基础,这些基础大概包括下面两点:

学过c语言,汇编;

对微控制器有一定了解。

一般理工类(计算机,自动化,电子类专业)的学生大三学比较合适。因为到了大三,一般学过了c语言及汇编,虽然大部分学生没有独立写过一个程序,但至少上过这门课,自己也看过相关知识点;而且上过8051等微控制器原理的课程,也看过类似的教课书。

具备以上基础的人,也不是谁都可以学。因为嵌入式学习门槛比较高,难度比较大,不但要有一定的毅力,而且要触类旁通,如果太死板也很难学会。

概括的说学习嵌入式还必备下列性格:

热爱研发!

切忌浮躁!

执着,顽强,自信!

举一反三!

如果你符合以上条件,完全可以经过努力把嵌入式学好,我了解到的在华清远见学习的一个同学,之前基本上什么基础都没有,写一个“hello world”程序都为难,编译了几次才通过,但是经过四个月的努力,在华清远见专业老师和同学们的热心帮助下,从一个完全的菜鸟变成了入门级别的linux工程师了,找到了一份做应用开发的工作,工资大概有四千吧,还算不错。

LZ要自学的话,可以多到华清远见的网站上看看他们的课程设置,就知道自己该学些什么,还有很多学习资料和视频可以下载,另外华清远见出版的40多本嵌入式专业畅销书,外面各大书店和图书馆都有,你都可以去翻翻看看。

祝你早日学有所成!

请参考,希望能帮到你。

Ⅳ 做嵌入式原理课程设计 linux内核精简 是什么意思,该怎么做

OK 我发给你 .

Ⅵ 求嵌入式linux开发详细流程(步骤)

建立以Linux系统为基础的开发环境;

配置开发主机(MINICOM调试嵌入式开发板、NFS网络文件系统,防火墙);

建立引导装载程序BOOTLOADER(公开源代码的BOOTLOADER,如U-BOOT、BLOB、VIVI、LILO、ARM-BOOT、RED-BOOT等);

下载别人已经移植好的Linux操作系统(如μCLinux、ARM-Linux、PPC-Linux等);

建立根文件系统(包括:/etc/init.d/rc.S、/etc/profile、/etc/.profile等);

建立应用程序的Flash磁盘分区,一般使用JFFS2或YAFFS文件系统;

开发应用程序,应用程序可以放入根文件系统中,也可以放入YAFFS、JFFS2文件系统中;

烧写内核、根文件系统、应用程序、发布产品。

Ⅶ 嵌入式Linux课程设计源代码

Linux课程体系了解一来下:

Linux云计源算网络管理实战

Linux系统管理及服务配置实战

Linux Shell自动化运维编程实战

Linux云计算网络管理实战

大型网站高并发架构及自动化运维项目

网站安全渗透测试及性能调优项目实战

公有云运维技术项目实战

企业私有云架构及运维实战

Python自动化运维开发基础

Python自动化运维开发项目实战

Ⅷ 嵌入式ARM/LINUX毕业设计

有办法的话找个附近的嵌入式公司选他们的板子在上面做个小扩展性开发。最好选嵌入式教授采购实验设备的代理 之类的,甚至可以“开发”一款他们已有的功能,抄一下写个论文即可。

Ⅸ 学习嵌入式linux流程

嵌入式学习是一个循序渐进的过程,有C语言基础还是比较好的,C++的话不搞上层应用就用不上,如果是希望向嵌入式Linux方向发展的话,关于这个方向,我认为大概分3个阶段:

1、嵌入式linux上层应用,包括QT的GUI开发

2、嵌入式linux系统开发

3、嵌入式linux驱动开发

嵌入式目前主要面向的几个操作系统是,LINUX,WINCE、VxWorks等等

Linux是开源免费的,而且其源代码是开放的,更加适合我们学习嵌入式。

你可以尝试以下路线:

(1) C语言是所有编程语言中的强者,单片机、DSP、类似ARM的种种芯片的编程都可以用C语言搞定),因此必须非常熟练的掌握。

推荐书籍:《The C Programming Language》 这本经典的教材是老外写的,也有中译版本。

(2) 操作系统原理,是必需的,如果你是计算机专业毕业那也就无所谓了,如果是非计算机专业的就必须找一本比较浅显的计算机原理书籍看一看,把啥叫“进程”“线程”“系统调度”等等基本问题搞清楚。

(3)Linux操作系统就是用C语言编写的,所以你也应该先学习下Linux方面的编程,只有你会应用了,才能近一步去了解其内核的精髓。

推荐书籍:《UNIX环境高级编程》(第2版)

(4) 了解ARM的架构,原理,以及其汇编指令,我们在嵌入式开发中,一般很少去写汇编,但是最起码的要求是能够看懂arm汇编。

(5) 系统移植的时候,就需要你从最下层的bootloader开始,然后内核移植,文件系统移植等。而移植这部分对硬件的依赖是非常大的,其配置步骤也相对复杂,也没有太多详细资料。

(6) 驱动开发

linux驱动程序设计既是个极富有挑战性的领域,又是一个博大精深的内容。

linux驱动程序设计本质是属于linux内核编程范畴的,因而是对linux内核和内核编程是有要求的。在学习前你要想了解linux内核的组成,因为每一部分要详细研究的话足够可以扩展成一本厚书。

以上只不过是大概的框架,在实际的开发中还会涉及很多东西,比如:交叉编译、makefile、shell脚本等等,所以说学习嵌入式的周期较长,门槛较高,自学的话更是需要较强的学习能力和专业功底。只要能坚持下来一定会取得成功!

其实LZ可以到一些嵌入式培训机构的网站上看一下他们的课程设置,就会在脑子里有个清晰的思路,比如华清远见的官方网站,上面的嵌入式内容很丰富,嵌入式方面的信息更新也很迅速,没事可以去转转。

Ⅹ 求嵌入式Linux 课程设计,随便什么题目,用C或C++写的!要有完整的源代码,有实验报告就更好了!

网上很多啊,自己去搜一个就好了,但是要改动一下,不然会重复的...弱弱的问一下,你是南京某高校的么?

LINUX操作系统课程设计:企业服务器的配置与实现怎样做

一般购买大品牌的服务器才有相应的驱动程序:

硬件:4核CPU,4G的内存,主板带RIAD,512G内存,

安装与配置Web服务器

Apache服务器源代码安装:

Apache RPM软件下载:

Apache模块和MPM可使用类型的更详细介绍:

Apache对模块的使用有两种方法,一种是将其永久性地编译Apache内核中,即采用静态编译;另一种是采取动态编译,将其编译成DSO(Dynamic shared object,动态共享对象)模块,DSO模块的存储是独立于内核的,可被内核在需要时调用,具体是由mod_so模块提供的运行时配置指令(LoadModule)来实现的,若在编译中包含有任何动态模块,则mod_so模块会被自动包含进内核。若仅希望内核能够支持装载DSO模块,但不实际编译任何动态模块,则在编译配置时就明确指定--enable-so配置参数。

还提供了多道处理模块MPMs(multi-processing modules),编译过程中必须包含一个且只能有一个MPM,编译时系统会根据平台类型自动选择使用默认的MPM,也可在configure命令行中配置:

--with-mpm=要使用MPM类型

模块的指定方法:

1.静态编译模块到内核中,如编译包含mod-sll和mod_rewrite(去掉mod_)模块:

./configure --enable-module="ssl rewrite"或./configure --enable-sll --enable-rewrite

动态编译模块为DSO:

./configure --enable-mods-shared="ssl rewrite"或./configure --enable-rewrite=shared

模块说明:

httpd -l //查看httpd进程中包含哪些模块;

httpd -S //检查虚拟主机的配置是否存在语法错误;

httpd -f //启动httpd守护进程时,加载配置文件;

mod_deflate模块允许支持此功能的浏览器,在请求的页面内容发送前进行压缩,以节少网络带宽。

mod_vbost_alias模块支持虚拟主要的动态配置。

chkconfig --level 235 httpd on

chkconfig --list httpd

service httpd start

service httpd restart

service httpd reload //重新装载httpd.conf(不重启服务器)

./configure --prefix=/usr/local/apache2 --enable-so --with-mpm=prefork --enable-modules="setenvif rewrite deflate vhost_alias"

#apachectl start //启动Apache服务器;

#apachectl restart

#echo "/usr/local/apache2/bin/apachectl start"/etc/rc.d/rc.local //自动启动

#httpd -t //检查配置文件httpd.conf

#apachect configtest //检查配置文件httpd.conf

#ServerRoot apache安装路径 //设置服务器的根目录;

#ServerName 完整的域名[:端口号] //设置服务器用于重定向(端口)和虚拟主机;

#Listen [IP地址]端口号 //告诉服务器接受来自指定端口或者指定IP地址的某端口的请求;

Listen 80

Listen 61.186.160.104:8088

#ServrAdmin E-mail地址 //设置Web站点管理员的E-mail地址,当产生错误时(如指定的网页找不到),服务器返回给客户端的

错误信息中将包含该邮件地址,以告诉用户该向谁报告错误;

#DocumentRoot 目录路径名 //设置Web服务器站点根目录;

DocumentRoot /usr/local/apache2/htdocs

#ErrorDocument 错误号 所要显示的网页 //定义当遇到错误时,服务器将给客户端什么样的回应,通常是显示预设置的一个错误页面;

grep ErrorDocument /etc/httpd/conf/httpd.conf //httpd.conf中一些对不同错误的响应信息;

#DirectoryIndex index.php index.htm index.html default.htm //设置站点主页文件的搜索顺序;

#user nobody //设置服务器以哪种(nobody)用户身份来响应客户端的请求;

#Group # -1 //设置服务器以哪种(nobody)用户身份来响应客户端的请求;nobody用户权限较小。

#AddDefaultCharset GB2312 //指定默认的字符集;

#TimeOut //设置连接请求超时的时间(秒),超时将断开;

#KeepAlive //用于启用持续的连接或者禁用;KeepAlive On|Off

#MaxKeepAliveRequests //设置在一个持续连接期间允许的最大HTTP请求数目;

#KeepAliveTimeout //设置在关闭TCP连接之前,等待后续请示求的秒数;一旦接受请求建立了TCP连接后则开始计时;

#PidFile logs/httpd.pid //指定存放httpd主(父)进程号的文件名;

日志配置命令:

#ErrorLog //指定服务器存放错误日志文件的位置和文件名;

#LogLevel //设置记录在错误日志中的信息的详细程序;

emerg 紧急,系统将无法使用;

alert 必须立即采取措施;

crit 致命情况;

crror 错误情况;

warm 警告;

info 普通信息;

notice 一般重要情况;

debug 出错级别信息;

//测试Apache是否正常运行

Test Page

This page is used to test the proper operation of the Apache Web server after it has been installed. If you can read this page, it means that the Apache Web server installed at this site is working properly.

#rpm -q httpd

#rpm -Uvh http-2.0.40-21.11.i386.rpm

目录说明:

/etc/httpd/conf //Apache服务器的配置文件httpd.conf

/etc/rc.d/init.d/ //Apache服务器启动脚本安装,httpd

/var/www/html //Web站点根目录;

/usr/bin //Apache软件包提供的可执行程序安装在该目录下。

/etc/httpd/logs //日志文件

htdocs //默认Web站点的根目录,可通过配置文件httpd.conf进行设置或更改;

cgi-bin //CGI脚本目录;

bin //apachectl启动脚本会自动设置在某些操作系统下,正常运行httpd所需的环境变量;

httpd守扩进程被调用后做的第一件事就是读取httpd.conf,并根据其配置项来配置当前Web服务器;

httpd.conf 分为三部分(section),

第一部分为全局环境设置,主要用于设置ServerRoot、主进程号的保存文件、

对进程的控制、服务器侦听的IP地址、端口、要装载的DSO模块

第二部分是服务器的主要配置指一位置;

第三部分用于设置和创建虚拟主机;

Listen 80 //Web服务器绑定在80端口;

DocumentRoot //设置Web站点的根目录等;

访问控制指令:

Directory /usr/local/*/htdoes //Directory使指定的目录及其子目录有效;不可嵌套。目录名可使用“*”或“?”通配符,

Files ~“\.ht" //作用于指定的文件,则不管该文件实际存在子哪个目录,允许所有主机访问位于任何目录下的.ht开的文件

Order allow,deny //指定allow和deny语句,哪一个被执行;允许、禁止访问主机。

Allow from all //允许所有主机访问;也可以是IP地址。

Files

/Directory

Location /assistant //针对URL地址进行访问限制,不是文件系统;

Order deny,allow //

Deny from all

Allow from 61.186.160.105

/Location

Order deny,allow //若主机没有被特别指出拒绝访问,则该资源被允许访问。

Order allow,deny //若主机没有被特别指出允许访问,则该主要将被拒绝访问该资源。

Order mntual-failure //只有那些在allow语句中被指定,同时又没有出现在deny语句的主机,才允许访问。若主机在两条指

令中都没有出现,则将被拒绝访问;

*、? //*代表任意个字符,?代表一个任意的字符;

DirectoryMatch //指定目录名时,可直接使用正则表达式;Directory若要使用正则表达式,则需要在正则表达式前加“~"

FilesMatch //可直接使用正则表达式来通配多个文件;

AccessFileName .htaccess //.htaccess分布式配置文件,在该文件中也可放置一些配置指令,以作用于该文件所在的目录以及

其下的所有子目录。搜寻.htaccess文件会降低系统性能;

Directory /

AllowOverride None //禁止系统查找.htaccess文件;

Options FollowSymLinks //Options:控制在特定目录中将使用哪些服务器特性;

/Directory

Options命令可用的选项:

None 不启用任何额处特性;

All 除MultiViews之外的所有特性,默认设置;

ExecCGI 允许执行CGI脚本;

FollowSymLinks 服务器允许在此目录中使用符号连接。在Location段中无效

Includes 允许服务器端包含SSI(Server-side includes)

IncludesN()EXEC 允许服务器端包含,但禁用#exec和#exec CGI命令。但仍可以从ScriptAltase目录使用#include虚拟CGI脚本;

Indexes 如果一个映射目录的URL被请求,而此目录中又没有DirectoryIndex(如:index.html),那么服务器返回一个

格式化后的目录列表;

MultiViews 允许内容协商的多重视图;

SymLinksIfOwnerMatch 服务器仅在符号连接与其目的目录或文件拥有者具有同样的用户ID时,才使用它;

ExecCGI 拥有ExecCGI执行权限;

prefork.c 控制Apache进程,对于使用prefork多道处理模块的Apache服务器;

IfModule prefork.c

StartServers 5 //设置服务器启动时启动的子进程的个数;

MinSpareServers 5 //设置服务器中空闲子进程(即没有HTTP处理请求的子进程)数目的下限;

MaxSpareServers 10 //设置服务器中空闲子进程数目的上限。若空闲子进程超过该设置值,则父进程就会

停止多余的子进程;

MaxClients 150 //设置服务器允许连接的最大客户数;

MaxRequestsPerChild 0 //设置子进程所能处理请求的数目上限,0为不受限制;

/IfModule

access_log //日志文件用于记录服务器处理的所有请求;

CustomLog 指定access_log日志文件的位置和日志记录的格式;

LogFormat 定义日志的记录格式;

LogFormat 日志格式字符串 日志格式名称

LogFormat "%h %1 %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined;

LogFormat "%h %1 %u %t \"%r\" %s %b" common;

LogFormat "%{Referer}i-%U" referer;

LogFormat "%{User-agent}i“ agent;

LogFormat logs/access_log common

LogFormat "%v %h %l %u %t \"%r"\ %s %b" vhost

CustomLog logs/vhost_log vhost

%a 远程主机IP地址

%A 本地主机IP地址

%h 远程主机名

%H 请求协议

%l 远程登录名

%u 来自auth 的远程用户

%U 请求的URL路径

%U{User-agent}i 用户浏览器类型

%b 发送的字节数,不包括HTTP标题

%t 请求的时间

%r HTTP请求的第一行的内容

%s HTTP响应状态码,200代表访问成功,404代表文件未找到,403代表禁止访问,401代表未授权访问,400代表错误请求。

%m 请求方法

%v 服务于该请求的服务器的ServerName

%V 服务器的名字,取决于UseCanonicalName的设置

%{Host}i 返回HTTP请求的主机头信息,可能含端口号信息

split-logfile /var/www/myweb/vhost_log //当所有虚拟机日志都记录在主站点日志中时,使用此命令将日志按虚拟主机名分组,拆分成一个个独立的日

志文件,第个日志文件采用"虚拟主机名.log“形式命名,其中包含了该虚拟主机所产生的日志记录;

容器与访问控制指令:容器指令通常用于封装一组指令,使其在容器条件成立时有效,或者用于改变指令的作用域。

IfModue ! mpm_winnt.c //IfModue用于判断指定的模块是否存在,若存在(被静态地编译进服务器,或是被动态装载进服务器)则包含于

其中的指令将有效,否则会被忽略。可嵌套使用。

IfModue ! mpm_netware.c //若要使模块不存在时所包含的指令有效,只需在模块名前加一个“!”即可,

User nobody

Group # -1

/IfModue

/IfModue

基于域名虚拟主机:

例:假设当前服务器的IP地址为192.168.3.120,现要在该服务器创建两个基于域名的虚拟主机,使用端口为标准的80,其域名分别为和,站点根目录分别为/var/www/myweb1和/var/www/myweb2,日志文件分别放在/var/vhlogs/myweb1和/var/vhlogs/myweb2目录下面,Apache服务器原来的主站点采用域名进行访问。

#vi /etc/hosts //使用/etc/hosts进行域名注册;

192.168.3.120

#ping //检测域名解析是否正常;

#ping

#ping

#mkdir -p /var/www/myweb1

#mkdir -p /var/www/myweb2

#mkdir -p /var/vhlogs/myweb1

#mkdir -p /var/vhlogs/myweb2

#vi /etc/httpd/conf/httpd.conf

Listen 80 //设置Listen指令侦听的端口

NameVirtualHost 192.168.3.120 //基于域名的虚拟主机,如果对多个地址使用了多个基于域名的虚拟主机

则对每个地址均要使用此指令:NameVirtualHost IP地址:端口

NameVirtualHost * 当IP地址无法确定时,使用“*”通配任意的IP地址

VirtualHost 192.168.3.120 //定义一个虚拟主机,VirtualHost的参数必须与NameVirtualHost后面所使用的参数保持一致。

ServerName //当一个请求到时,服务器会首先检查它是否使用了一个能和NameVirtualHost相匹配的IP地址。如果匹配,就会

DocumentRoot /usr/local/apache/htdoes //就会查找每个与这个IP地址相对应的VirtualHost配置段,并尝试找出一个ServerName或ServerAlias配置相

ServerAdmin yjghddii@126.com //与请求的主机名(域名)相同的,若找到,则使用该虚拟主机的配置,并响应其访问请求。否则将使用符合这个

/VirtualHost //IP地址的第一个列出的虚拟主机。在最前面的虚拟主机成为默认虚拟主机。

VirtualHost 192.168.3.120

ServerName

DocumentRoot /var/www/myweb1

DirectoryIndex index.php index.php3 index.html index.htm default.html default.html

ServerAdmin yjghddii@126.com

ErrorLog /var/vhlogs/myweb/error_log

TransferLog /var/vhlogs/myweb1/access_log

/VirtualHost

VritualHost 192.168.3.200

ServerName

DocumenRoot /var/www/myweb2

DirectoryIndex index.php index.php3 index.htm index.html default.htm default.html

ServerAdmin yjghddii@126.com

ErrorLog /var/vhlogs/myweb2/error_log

TranferLog /var/vhlogs/myweb2/access_log

/VirtualHost

Directory /var/www //对Web站点目录设置访问控制;

Options FllowSymLinks

AllowOverride None

Order deny,allow

Allow from all

/Directory

Apachectl –S //查查虚拟主机配置是否正确;

Aparhectl restart //重启Apache服务器配置生效;

例:

NameVirtualHost 192.168.168.10 //服务器配有两块网卡,IP:内网192.168.168.10,外网61.186.160.104,在Internet网中,企业域名

NameVirtualHost 61.186.160.104 //指向外网IP地址,在企业内网的DNS服务器中,指向内网IP地址;现要求为来自内网

VirtualHost 192.168.168.10 61.186.160.104 //外网的请求提供同样的Web服务。(httpd.conf中设置)

DocumentRoot /www/server1

ServerName

/Virtual

例:

Listen 80 //服务器:192.168.168.154,服务器上创建两个基于域名(主机名)的虚拟主机,域名:和www.

Listen 8080 //myweb4.com,每个虚拟主机的80端口和8080端口,分别服务一个Web站点,其站点根目录分别为

// /var/www/myweb3-80、/var/www/myweb3-8080、/var/www/myweb4-80、/var/www/myweb4-8080。

NameVirtualHost 192.168.168.154:80 //的80端口作为默认Web站点。

NameVirtualHost 192.168.168.154:8080

VirtualHost 192.168.168.154:80

ServerName

DocumentRoot /var/www/myweb3-80

VirtualHost

VirtualHost 192.168.168.154:8080

ServerName

DocumentRoot /var/www/myweb3-8080

/VirtualHost

VirtualHost 192.168.168.154:80

ServerName

DocumentRoot /var/www/myweb4-80

/VirtualHost

VirtualHost 192.168.168.154:8080

ServerName

DocumentRoot /var/www/myweb4-8080

/VirtualHost

基于IP地址虚拟主机:

#cd /etc/sysconfig/network-scripts //服务器有两张网卡eth0、eth1,eth0:192.168.167.157,

#cp ifctg-eth1 ifcfg-eth1:0 //eth1:192.168.167.156.eth0网卡用作了基于主机名的虚拟主机,

#vi ifcfg-eth1:0 //eth1通过IP别名方式,为其绑定多个IP地址,用于提供基于IP地址

DEVICE=eth1:0 //的虚拟主机。eth1绑定的第一张虚拟网卡的设备名为eth1:0,对应的

IPADDR=192.168.167.157 //配置文件为ifcfg-eth1:0,通过修改配置文件中的设备名和IP地址,

#ifdown eth1 //即可实现IP地址的绑定。

#ifup eth1:0

#ifup eth1

#ping 192.168.167.157

#ping 192.168.167.156

#vi /etc/hosts //192.168.167.156::

192.168.167.157 //,试为其创建基于IP地址的虚拟主机,端口使用80

#mkdir -p /var/www/example2 //目录分别为/var/www/example2、/var/www/example3,为这两个域再增

#mkdir -p /var/www/example3 //8080端口,使其也能在8080端口发布另外的Web站点。Web站点根目录分

///var/www/example2-8080、/var/www/example3-8080

#vi httpd.conf

Listen 80

Listen 8080

VirtualHost 192.168.167.156:80

ServerName

DocumentRoot /var/www/example2

/VirtualHost

VirtualHost 192.168.167.156:8080

ServerName

DocumentRoot /var/www/example2-8080

/VirtualHost

VirtualHost 192.168.167.157:80

ServerName

DocumentRoot /var/www/example3

/VirtualHost

VirtualHost 192.168.167.157:8080

ServerName

DocumentRoot /var/www/example3-8080

/VirtualHost

Unix课程设计 基于Linux内核的防火墙的分析与设计

一、什么是状态机

有限状态机是一种用来进行对象行为建模的工具,其作用主要是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。在面向对象的软件系统中,一个对象无论多么简单或者多么复杂,都必然会经历一个从开始创建到最终消亡的完整过程,这通常被称为对象的生命周期。一般说来,对象在其生命期内是不可能完全孤立的,它必须通过发送消息来影响其它对象,或者通过接受消息来改变自身。在大多数情况下,这些消息都只不过是些简单的、同步的方法调用而已。例如,在银行客户管理系统中,客户类(Customer)的实例在需要的时候,可能会调用帐户(Account)类中定义的getBalance()方法。在这种简单的情况下,类Customer并不需要一个有限状态机来描述自己的行为,主要原因在于它当前的行为并不依赖于过去的某个状态。

遗憾的是并不是所有情况都会如此简单,事实上许多实用的软件系统都必须维护一两个非常关键的对象,它们通常具有非常复杂的状态转换关系,而且需要对来自外部的各种异步事件进行响应。例如,在VoIP电话系统中,电话类(Telephone)的实例必须能够响应来自对方的随机呼叫,来自用户的按键事件,以及来自网络的信令等。在处理这些消息时,类Telephone所要采取的行为完全依赖于它当前所处的状态,因而此时使用状态机就将是一个不错的选择。

游戏引擎是有限状态机最为成功的应用领域之一,由于设计良好的状态机能够被用来取代部分的人工智能算法,因此游戏中的每个角色或者器件都有可能内嵌一个状态机。考虑RPG游戏中城门这样一个简单的对象,它具有打开(Opened)、关闭(Closed)、上锁(Locked)、解锁(Unlocked)四种状态,如图1所示。当玩家到达一个处于状态Locked的门时,如果此时他已经找到了用来开门的钥匙,那么他就可以利用它将门的当前状态转变为Unlocked,进一步还可以通过旋转门上的把手将其状态转变为Opened,从而成功地进入城内。

图1 控制城门的状态机

在描述有限状态机时,状态、事件、转换和动作是经常会碰到的几个基本概念。

状态(State) 指的是对象在其生命周期中的一种状况,处于某个特定状态中的对象必然会满足某些条件、执行某些动作或者是等待某些事件。"

事件(Event) 指的是在时间和空间上占有一定位置,并且对状态机来讲是有意义的那些事情。事件通常会引起状态的变迁,促使状态机从一种状态切换到另一种状态。

转换(Transition) 指的是两个状态之间的一种关系,表明对象将在第一个状态中执行一定的动作,并将在某个事件发生同时某个特定条件满足时进入第二个状态。

动作(Action) 指的是状态机中可以执行的那些原子操作,所谓原子操作指的是它们在运行的过程中不能被其他消息所中断,必须一直执行下去。

二、手工编写状态机

与其他常用的设计模式有所不同,程序员想要在自己的软件系统中加入状态机时,必须再额外编写一部分用于逻辑控制的代码,如果系统足够复杂的话,这部分代码实现和维护起来还是相当困难的。在实现有限状态机时,使用switch语句是最简单也是最直接的一种方式,其基本思路是为状态机中的每一种状态都设置一个case分支,专门用于对该状态进行控制。下面的代码示范了如何运用switch语句,来实现图1中所示的状态机:

switch (state) {

// 处理状态Opened的分支

case (Opened): {

// 执行动作Open

open();

// 检查是否有CloseDoor事件

if (closeDoor()) {

// 当前状态转换为Closed

changeState(Closed)

}

break;

}

// 处理状态Closed的分支

case (Closed): {

// 执行动作Close

close();

// 检查是否有OpenDoor事件

if (openDoor()) {

// 当前状态转换为Opened

changeState(Opened);

}

// 检查是否有LockDoor事件

if (lockDoor()) {

// 当前状态转换为Locked

changeState(Locked);

}

break;

}

// 处理状态Locked的分支

case (Locked): {

// 执行动作Lock

lock();

// 检查是否有UnlockDoor事件

if (unlockDoor()) {

// 当前状态转换为Unlocked

changeState(Unlocked);

}

break;

}

// 处理状态Unlocked的分支

case (Unlocked): {

// 执行动作Unlock

unlock();

// 检查是否有LockDoor事件

if (lockDoor()) {

// 当前状态转换为Locked

changeState(Locked)

}

// 检查是否有OpenDoor事件

if (openDoor()) {

// 当前状态转换为Opened

changeSate(Opened);

}

break;

}

}

使用switch语句实现的有限状态机的确能够很好地工作,但代码的可读性并不十分理想,主要原因是在实现状态之间的转换时,检查转换条件和进行状态转换都是混杂在当前状态中来完成的。例如,当城门处于Opened状态时,需要在相应的case中调用closeDoor()函数来检查是否有必要进行状态转换,如果是的话则还需要调用changeState()函数将当前状态切换到Closed。显然,如果在每种状态下都需要分别检查多个不同的转换条件,并且需要根据检查结果让状态机切换到不同的状态,那么这样的代码将是枯燥而难懂的。从代码重构的角度来讲,此时更好的做法是引入checkStateChange()和performStateChange()两个函数,专门用来对转换条件进行检查,以及激活转换时所需要执行的各种动作。这样一来,程序结构将变得更加清晰:

switch (state) {

// 处理状态Opened的分支

case (Opened): {

// 执行动作Open

open();

// 检查是否有激发状态转换的事件产生

if (checkStateChange()) {

// 对状态机的状态进行转换

performStateChange();

}

break;

}

// 处理状态Closed的分支

case (Closed): {

// 执行动作Close

close();

// 检查是否有激发状态转换的事件产生

if (checkStateChange()) {

// 对状态机的状态进行转换

performStateChange();

}

break;

}

// 处理状态Locked的分支

case (Locked): {

// 执行动作Lock

lock();

// 检查是否有激发状态转换的事件产生

if (checkStateChange()) {

// 对状态机的状态进行转换

performStateChange();

}

break;

}

// 处理状态Unlocked的分支

case (Unlocked): {

// 执行动作Lock

unlock();

// 检查是否有激发状态转换的事件产生

if (checkStateChange()) {

// 对状态机的状态进行转换

performStateChange();

}

break;

}

}

但checkStateChange()和performStateChange()这两个函数本身依然会在面对很复杂的状态机时,内部逻辑变得异常臃肿,甚至可能是难以实现。

在很长一段时期内,使用switch语句一直是实现有限状态机的唯一方法,甚至像编译器这样复杂的软件系统,大部分也都直接采用这种实现方式。但之后随着状态机应用的逐渐深入,构造出来的状态机越来越复杂,这种方法也开始面临各种严峻的考验,其中最令人头痛的是如果状态机中的状态非常多,或者状态之间的转换关系异常复杂,那么简单地使用switch语句构造出来的状态机将是不可维护的。

三、自动生成状态机

为实用的软件系统编写状态机并不是一件十分轻松的事情,特别是当状态机本身比较复杂的时候尤其如此,许多有过类似经历的程序员往往将其形容为"毫无创意"的过程,因为他们需要将大量的时间与精力倾注在如何管理好状态机中的各种状态上,而不是程序本身的运行逻辑。作为一种通用的软件设计模式,各种软件系统的状态机之间肯定会或多或少地存在着一些共性,因此人们开始尝试开发一些工具来自动生成有限状态机的框架代码,而在Linux下就有一个挺不错的选择——FSME(Finite State Machine Editor)。

图2 可视化的FSME

FSME是一个基于Qt的有限状态机工具,它能够让用户通过图形化的方式来对程序中所需要的状态机进行建模,并且还能够自动生成用C 或者Python实现的状态机框架代码。下面就以图1中城门的状态机为例,来介绍如何利用FSME来自动生成程序中所需要的状态机代码。

3.1状态机建模

首先运行fsme命令来启动状态机编辑器,然后单击工具栏上" "New"按钮来创建一个新的状态机。FSME中用于构建状态机的基本元素一共有五种:事件(Event)、输入(Input)、输出(Output)、状态(State)和转换(Transition),在界面左边的树形列表中可以找到其中的四种。

状态建模

在FSME界面左边的树形列表中选择"States"项,然后按下键盘上的Insert键来插入一个新的状态,接着在右下方的"Name"文本框中输入状态的名称,再在右上方的绘图区域单击该状态所要放置的位置,一个新的状态就创建好了。用同样的办法可以添加状态机所需要的所有状态,如图3所示。

图3 状态建模

事件建模

在FSME界面左边的树形列表中选" "Events"项,然后按下键盘上的Insert键来添加一个新的事件,接着在右下方的"Name"文本框中输入事件的名称,再单击"Apply"按钮,一个新的事件就创建好了。用同样的办法可以添加状态机所需要的所有事件,如图4所示。

图4 事件建模

转换建模

状态转换是整个建模过程中最重要的一个部分,它用来定义有限状态机中的一个状态是如何切换到另一个状态的。例如,当用来控制城门的状态机处于Opened状态时,如果此时有Close事件产生,那么状态机的当前状态将切换到Closed状态,这样一个完整的过程在状态机模型中可以用closeDoor这样一个转换来进行描述。

要在FSME中添加这样一个转换,首先需要在界面左边的树形列表中选" "States"下的"Opened"项,然后按下键盘上的Insert键来添加一个新的转换,接着在右下角的"Name"文本框中输入转换的名字"closeDoor",在"Condition"文本框中输入"Close"表明触发该转换的条件是事件Close的产生,在"Target"下拉框中选择"Closed"项表明该转换发生后状态机将被切换到Closed状态,最后再单击"Apply"按钮,一个新的状态转换关系就定义好了,如图5所示。用同样的办法可以添加状态机所需要的所有转换。

图5 转换建模

3.2" 生成状态机框架

使用FSME不仅能够进行可视化的状态机建模,更重要的是它还可以根据得到的模型自动生成用C 或者Python实现的状态机框架。首先在FSME界面左边的树形列表中选择"Root"项,然后在右下角的"Name"文本框中输入状态机的名字"DoorFSM",再从"Initial State"下拉列表中选择状态"Opened"作为状态机的初始化状态,如图6所示。

图6 设置初始属性

在将状态机模型保存为door.fsm文件之后,使用下面的命令可以生成包含有状态机定义的头文件:

$ fsmc door.fsm -d -o DoorFSM.

进一步还可以生成包含有状态机实现的框架代码:

$ fsmc door.fsm -d -impl DoorFSM.h -o DoorFSM.cpp

如果想对生成的状态机进行验证,只需要再手工编写一段用于测试的代码就可以了:

/*

* TestFSM.cpp

* 测试生成的状态机框架

*/

#include "DoorFSM.h"

int main()

{

DoorFSM door;

door.A(DoorFSM::Close);

door.A(DoorFSM::Lock);

door.A(DoorFSM::Unlock);

door.A(DoorFSM::Open);

}

有限状态机是由事件来进行驱动的,在FSME生成的状态机框架代码中,方法A()可以被用来向状态机发送相应的事件,从而提供状态机正常运转所需要的"动力"。状态机负责在其内部维护一个事件队列,所有到达的事件都会先被放到事件队列中进行等候,从而能够保证它们将按照到达的先后顺序被依次处理。在处理每一个到达的事件时,状态机都会根据自己当前所处的状态,检查与该状态对应的转换条件是否已经被满足,如果满足的话则激活相应的状态转换过程。

使用下面的命令能够将生成的状态机框架和测试代码编译成一个可执行文件:

$ g DoorFSM.cpp TestFSM.cpp -o fsm

由于之前在用fsmc命令生成状态机代码时使用了-d选项,生成的状态机框架中会包含一定的调试信息,包括状态机中每次状态转换时的激活事件、转换前的状态、所经历的转换、转换后的状态等,如下所示:

$ ./fsm

DoorFSM:event:'Close'

DoorFSM:state:'Opened'

DoorFSM:transition:'closeDoor'

DoorFSM:new state:'Closed'

DoorFSM:event:'Lock'

DoorFSM:state:'Closed'

DoorFSM:transition:'lockDoor'

DoorFSM:new state:'Locked'

DoorFSM:event:'Unlock'

DoorFSM:state:'Locked'

DoorFSM:transition:'unlockDoor'

DoorFSM:new state:'Unlocked'

DoorFSM:event:'Open'

DoorFSM:state:'Unlocked'

DoorFSM:transition:'openDoor'

DoorFSM:new state:'Opened'

3.3 定制状态机

目前得到的状态机已经能够响应来自外部的各种事件,并适当地调整自己当前所处的状态,也就是说已经实现了状态机引擎的功能,接下来要做的就是根据应用的具体需求来进行定制,为状态机加入与软件系统本身相关的那些处理逻辑。在FSME中,与具体应用相关的操作称为输出(Output),它们实际上就是一些需要用户给出具体实现的虚函数,自动生成的状态机引擎负责在进入或者退出某个状态时调用它们。

仍然以控制城门的那个状态机为例,假设我们希望在进入每个状态时都添加一部分处理逻辑。首在FSME界面左边的树形列表选择"Outputs"项,然后按下键盘上的Insert键来添加一个新的输出,接着在右下方的"Name"文本框中输入相应的名称,再单击"Apply"按钮,一个新的输出就创建好了,如图7所示。用同样的办法可以添加状态机所需要的所有输出。

图7 添加输出

当所有的输出都定义好之后,接下来就可以为状态机中的每个状态绑定相应的输出。首先在FSME界面左侧的"States"项中选择相应的状态,然后从右下角的"Available"列表框中选择与该状态对应的输出,再单击""按钮将其添加到"In"列表中,如图8所示。用同样的办法可以为状态机中的所有状态设置相应的输出,同一个状态可以对应有多个输出,其中In列表中的输出会在进入该状态时被调用,而Out列表中的输出则会在退出该状态时被调用,输出调用的顺序是与其在In或者Out列表中的顺序相一致的。

图8 为状态设置输出

由于对状态机模型进行了修改,我们需要再次生成状态机的框架代码,不过这次不需要加上-d参数:

$ fsmc door.fsm -o DoorFSM.h

$ fsmc door.fsm -d -impl DoorFSM.h -o DoorFSM.cpp

我们在新的状态机模型中添加了enterOpend、enterClosed、enterLocked和enterUnlocked四个输出,因此生成的类DoorFSM中会包含如下几个纯虚函数

virtual void enterOpened() = 0;

virtual void enterLocked() = 0;

virtual void enterUnlocked() = 0;

virtual void enterClosed() = 0;

显然,此时生成的状态机框架不能够再被直接编译了,我们必须从类DoorFSM派生出一个子类,并提供对这几个纯虚函数的具体实现:

/*

* DoorFSMLogic.h

* 状态机控制逻辑的头文件

*/

#include "DoorFSM.h"

class DoorFSMLogic : public DoorFSM

{

protected:

virtual void enterOpened();

virtual void enterLocked();

virtual void enterUnlocked();

virtual void enterClosed();

};

正如前面所提到过的,这几个函数实际上代表的正是应用系统的处理逻辑,作为例子我们只是简单地输出一些提示信息:

/*

* DoorFSMLogic.cpp

* 状态机控制逻辑的实现文件

*/

#include "DoorFSMLogic.h"

#include iostream

void DoorFSMLogic::enterOpened()

{

std::cout "Enter Opened state." std::endl;

}

void DoorFSMLogic::enterClosed()

{

std::cout "Enter Closed state." std::endl;

}

void DoorFSMLogic::enterLocked()

{

std::cout "Enter Locked state." std::endl;

}

void DoorFSMLogic::enterUnlocked()

{

std::cout "Enter Unlocked state." std::endl;

}

同样,为了对生成的状态机进行验证,我们还需要手工编写一段测试代码:

/*

* TestFSM.cpp

* 测试状态机逻辑

*/

#include "DoorFSMLogic.h"

int main()

{

DoorFSMLogic door;

door.A(DoorFSM::Close);

door.A(DoorFSM::Lock);

door.A(DoorFSM::Unlock);

door.A(DoorFSM::Open);

}

使用下面的命令能够将生成的状态机框架和测试代码编译成一个可执行文件:

$ g DoorFSM.cpp DoorFSMLogic.cpp TestLogic.cpp -o logic

运行结果如下所示:

$ ./logic

Enter Closed state.

Enter Locked state.

Enter Unlocked state.

Enter Opened state.

四、小结

在面向对象的软件系统中,有些对象具有非常复杂的生命周期模型,使用有限状态机是描述这类对象最好的方法。作为一种软件设计模式,有限状态机的概念虽然不算复杂,实现起来也并不困难,但它的问题是当状态机的模型复杂到一定的程度之后,会带来实现和维护上的困难。Linux下的FSME是一个可视化的有限状态机建模工具,而且支持状态机框架代码的自动生成,借助它可以更加轻松地构建基于有限状态机的应用系统。

(责任编辑:IT教学网)

更多
上一篇:没有了

推荐微信营销文章