Linux 应用程序开发入门

Linux 应用程序开发入门

Neo Chen (netkiller)

<openunix@163.com>

版权 2011, 2012 http://netkiller.github.com

摘要

我会实现一个守护进程,从这个程序你将了解,Linux 应用程序开发基本流程

我们将实现一个远程shell的功能,可以通过tcp协议,运行远程机器上的命令或shell脚本

通过这个命令可以实现批量操作,管理上千台服务器。需要发挥你的想象力,灵活使用它。

写这个脚本,我是为了替代SSH远程操作,因为SSH不能控制运行命令,操作风险大,也不安全。

程序还不完善,还需要很多后续改进工作,比如通过SSL建立Socket链接,用户认证,ACL访问控制等等.

下面是我多年积累下来的经验总结,整理成文档供大家参考:

 

Netkiller Architect 手札 Netkiller Linux 手札 Netkiller Developer 手札 Netkiller Database 手札
Netkiller Debian 手札 Netkiller CentOS 手札 Netkiller FreeBSD 手札 Netkiller Shell 手札
Netkiller Web 手札 Netkiller Monitoring 手札 Netkiller Storage 手札 Netkiller Mail 手札
Netkiller Security 手札 Netkiller PostgreSQL 手札 Netkiller MySQL 手札 Netkiller LDAP 手札
Netkiller Cryptography 手札 Netkiller Intranet 手札 Netkiller Cisco IOS 手札 Netkiller Writer 手札
Netkiller Version 手札 Netkiller Studio Linux 手札    

 


目录

1. 环境2. nodekeeper 主程序2.1. 帮助信息2.2. 参数处理2.3. 后台运行2.4. 日志记录2.5. 多线程3. 配置文件4. init.d 脚本4.1. start/stop4.2. service start/stop

1. 环境

OS: Ubuntu 10.10

Python: 3.2.2

程序目录: /srv/nodekeeper

目录与相关文件

$ cd /srv
$ find nodekeeper | grep -v .svn
nodekeeper
nodekeeper/nodekeeper.ubuntu
nodekeeper/nodekeeper.cenos
nodekeeper/etc
nodekeeper/etc/commands.cfg
nodekeeper/etc/protocol.cfg
nodekeeper/bin
nodekeeper/bin/nodekeeper
nodekeeper/bin/console
		

2. nodekeeper 主程序

$ cat nodekeeper/bin/nodekeeper
#!/usr/bin/env python3
#/bin/env python3
#-*- coding: utf-8 -*-
##############################################
# Home  : http://netkiller.sf.net
# Author: Neo <openunix@163.com>
##############################################

import asyncore, asynchat, socket, threading
import subprocess, os, sys, getopt, configparser, logging
import string, re
from multiprocessing import Process

class Backend(asyncore.dispatcher):
    queue = []
    def __init__(self, host, port,config):
        asyncore.dispatcher.__init__(self)

        self.host = host
        self.port = port
        self.config = config

        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.bind((host,port))
        self.listen(10)

        try:
            cfg = Protocol(config['protocol'], self.host)
            #self.protocols = cfg.items(self.host)
            self.protocols = cfg.all()
            self.sections = cfg.sections()
        except configparser.NoSectionError as err:
            print("Error: %s %s" %(err, config['protocol']))
            sys.exit(2)
        try:
            logging.basicConfig(level=logging.NOTSET,
                    format='%(asctime)s %(levelname)-8s %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S',
                    filename=config['logfile'],
                    filemode='a')
            self.logging = logging.getLogger()
            #self.logging.debug('Test')
        except AttributeError as err:
            print("Error: %s %s" %(err, config['logfile']))
            sys.exit(2)

    def handle_accept (self):
        conn, addr = self.accept()
        self.queue.append(addr)
        request_handler(conn, self)
    def handle_connect(self):
        pass
    def handle_expt(self):
        self.close()
    def handle_close(self):
        self.close()

class request_handler(asynchat.async_chat):

    def __init__(self, sock, resource):
        asynchat.async_chat.__init__(self, sock=sock)
        self.sessions = resource
        self.buffer = b''
        self.set_terminator(b"\r\n")
        self.logging 	= resource.logging
        self.protocols 	= resource.protocols
        self.sections 	= resource.sections
        self.host 	= self.sessions.host

    def handle_connect(self):
        # connection succeeded
        #self.logging.info('')
        pass

    def handle_expt(self):
        # connection failed
        self.close()

    def collect_incoming_data(self, data):
        """Buffer the data"""
        #self.buffer.append(data)
        self.buffer = data

    def found_terminator(self):
        try:
            buffer = bytes.decode(self.buffer)
        except UnicodeDecodeError:
            print("\r\nError: ",err)
            buffer = ''
        try:
            execute = re.split(' ', buffer)
            command = execute[0]
            parameter = ' '.join( execute[1:])
            response = b''
            screen = ''
            if self.buffer == b'quit' or self.buffer == b'exit' :
                self.push(b'shutdown!!!\r\n')
                self.close_when_done()
            elif self.buffer == b'help' or self.buffer == b'?':
                screen = "Help may be requested at any point in a command by entering a question mark '?' or 'help'. the help list will be showing the available options.\r\n"

                for cmd,v in self.protocols :
                    screen += cmd + "\r\n"
            elif self.buffer == b'sections' :
                for sect in self.sections :
                    screen += sect + "\r\n"
            elif self.buffer == b'help.html' :
                for cmd,v in self.protocols :
                    screen += '<a href="?host='+self.host+'&cmd='+cmd+'">'+ cmd +'</a><br />' + "\r\n"
            elif self.buffer == b'enable':
                self.prompt = b'#'
            elif self.buffer == b'end' or self.buffer == b'^z':
                self.prompt = b'>'
            else:
                proto = dict(self.protocols)
                if command in proto :
                    run = proto[command] + ' ' + parameter
                    screen = subprocess.getoutput(run)

            if screen :
                response = bytes(screen + "\r\n",'utf8')
                self.push(response)
                self.logging.info(bytes.decode(self.buffer))
            self.buffer = b''
            self.close_when_done()
        except :
            self.close_when_done()
            sys.exit(2)

class Protocol():
    config = None
    agreement = None
    def __init__(self,cfg = 'protocol.cfg',sections = ''):
        self.config = configparser.SafeConfigParser()
        self.config.read(cfg)
        #self.agreement = self.config.items('common')
    def sections(self):
        return self.config.sections()
    def items(self, sections):
        self.agreement = self.config.items(sections)
        return self.agreement
    def dicts(self):
        return dict(self.agreement)
    def all(self):
        self.agreement = []
        for section in self.config.sections():
            self.agreement += self.config.items(section)
        return self.agreement

def main():
    daemon = False
    host = 'localhost'
    port = 7800
    pidfile = ''
    logfile = ''
    cfgfile = ''

    try:
        opts, args = getopt.getopt(sys.argv[1:], "h:p:d?v", [ "daemon","host=","port=", 'help',"h=","p=", "basedir=", "pidfile=", "config=", "protocol=", "logfile="])

        if not opts :
            usage()
            sys.exit()
        for o, a in opts :
            if o in ('-?', '--help') :
                usage()
                sys.exit()
            elif o in ("-v", "--verbose"):
                usage()
                sys.exit()
            elif o in ("-d", "--daemon"):
                daemon = True
            elif o in ("-h", "--host"):
                host = a
            elif o in ("-p", "--port"):
                port = int(a)
            elif o in ("--basedir"):
                BASEDIR = a
            elif o in ("--pidfile"):
                pidfile = a
            elif o in ("--config"):
                cfgfile = a
            elif o in ("--protocol"):
                protocol = a
            elif o in ("--logfile"):
                logfile = a
            else:
                assert False, "unhandled option"
    except getopt.GetoptError as err:
        # print help information and exit:
        usage()
        sys.exit(2)

    try:

        if daemon :
            pid = os.fork()
            if pid > 0:
                #exit first parent
                sys.exit(0)
        myself = str(sys.argv[0].split('/')[-1:][0])
        #pidfile = os.getpid()
        if not pidfile :
            pidfile = '/var/run/'+myself+'.pid'
        file = open(pidfile,'w')
        file.write(str(os.getpid()))
        file.close()
        if not cfgfile :
            cfgfile = ''+myself+'.cfg'
        if not logfile :
            logfile = '/var/log/'+myself+'.log'
        config = dict({'cfgfile':cfgfile, 'pidfile':pidfile, 'logfile':logfile, 'protocol':protocol})

        Backend(host,port,config)
        asyncore.loop(timeout=30, use_poll=True)

    except socket.error as err:
        print("\r\nError: ",err)
        sys.exit(2)
    except IOError as err:
        print("\r\nError: ",err)
        sys.exit(2)

def usage():
    myself = str(sys.argv[0].split('/')[-1:][0])

    print("Usage: %s -d -h <ip address> -p <7800>" % myself );
    print("Development and deployment administration platform")
    print("\r\nMandatory arguments to long options are mandatory for short options too.")
    print("\t-?, --help")
    print("\t-v, --verbose")
    print("\t-d, --daemon")
    print("\t-h, --host \t\t(default localhost)")
    print("\t-p, --port")
    print("\t    --config \t\t(default %s.cfg)" % myself)
    print("\t    --protocol \t\t(default %s.cfg)" % "protocol.cfg")
    print("\t    --pidfile \t\t(default /var/run/%s.pid)" % myself)
    print("\t    --logfile \t\t(default /var/log/%s.log)" % myself)
    print("\r\nExample:")
    print("\t%s --daemon --host localhost --port 7800" % myself)
    print("\t%s -d -h localhost -p 7800" % myself)
    print("\r\nSee http://netkiller.sf.net/ for updates, bug reports, and answers, \r\nif you have no web access, by sending email to Neo Chan<openunix@163.com>. ")
    # Exit status is 0 if OK, 1 if minor problems, 2 if serious trouble.

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print ("Crtl+C Pressed. Shutting down.")

2.1. 帮助信息

usage()

Usage: nodekeeper -d -h <ip address> -p <7800>
Development and deployment administration platform

Mandatory arguments to long options are mandatory for short options too.
	-?, --help
	-v, --verbose
	-d, --daemon
	-h, --host 		(default localhost)
	-p, --port
	    --config 		(default nodekeeper.cfg)
	    --protocol 		(default protocol.cfg.cfg)
	    --pidfile 		(default /var/run/nodekeeper.pid)
	    --logfile 		(default /var/log/nodekeeper.log)

Example:
	nodekeeper --daemon --host localhost --port 7800
	nodekeeper -d -h localhost -p 7800

See http://netkiller.sf.net/ for updates, bug reports, and answers,
if you have no web access, by sending email to Neo Chan<openunix@163.com>.

2.2. 参数处理

getopt.getopt 实现Unix风格的命令参数,例如:

nodekeeper --daemon --host localhost --port 7800

--host localhost --port 7800 IP地址与端口参数
--daemon 参数实现后台运行
			

具体实现代码

    try:
        opts, args = getopt.getopt(sys.argv[1:], "h:p:d?v", [ "daemon","host=","port=", 'help',"h=","p=", "basedir=", "pidfile=", "config=", "protocol=", "logfile="])

        if not opts :
            usage()
            sys.exit()
        for o, a in opts :
            if o in ('-?', '--help') :
                usage()
                sys.exit()
            elif o in ("-v", "--verbose"):
                usage()
                sys.exit()
            elif o in ("-d", "--daemon"):
                daemon = True
            elif o in ("-h", "--host"):
                host = a
            elif o in ("-p", "--port"):
                port = int(a)
            elif o in ("--basedir"):
                BASEDIR = a
            elif o in ("--pidfile"):
                pidfile = a
            elif o in ("--config"):
                cfgfile = a
            elif o in ("--protocol"):
                protocol = a
            elif o in ("--logfile"):
                logfile = a
            else:
                assert False, "unhandled option"
    except getopt.GetoptError as err:
        # print help information and exit:
        usage()
        sys.exit(2)

2.3. 后台运行

--daemon 参数实现后台运行,原理是首先通过os.fork()克隆一个进程,然后退出当前进程,克隆的新进程继续运行

如果是Shell程序,你可使用“&”符号后台运行,但作为一个应用程序,使用“&”显得不专业。

具体实现的代码如下

        if daemon :
            pid = os.fork()
            if pid > 0:
                #exit first parent
                sys.exit(0)

程序一旦进入后台,当前进程即将关闭,所以你必须保存PID,为后面的推出程序操作使用,这里我们可以通过 --pidfile 指定一个pid文件

2.4. 日志记录

程序一旦进入后台,你只能通过ps,pstree, top 等命令查看状态,运行情况必须通过日志的形式,打印出来

具体实现代码如下:

			logging.basicConfig(level=logging.NOTSET,
                    format='%(asctime)s %(levelname)-8s %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S',
                    filename=config['logfile'],
                    filemode='a')
            self.logging = logging.getLogger()
            self.logging.debug('Test')

2.5. 多线程

继承 asynchat.async_chat 实现多线程

class request_handler(asynchat.async_chat):

    def __init__(self, sock, resource):
        asynchat.async_chat.__init__(self, sock=sock)

连接数限制

        self.listen(10)
			

可以将这个参数提出来,然后通过命令行设置。

nodekeeper --daemon --maxconn 100 --host localhost --port 7800

self.max_connect = maxconn

self.listen(self.max_connect)
			

3. 配置文件

$ cat nodekeeper/etc/protocol.cfg
[system]
ls = ls
os.hosts = cat /etc/hosts
os.issue = cat /etc/issue
os.memory = free
os.who = who
os.harddisk = df -h
os.uptime = uptime
os.cpuinfo = cat /proc/cpuinfo
os.meminfo = cat /proc/meminfo
os.dmesg = dmesg
os.process = ps aux
os.summary = echo
network.status = netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
network.netstat = netstat -nlp
network.ifconfig = ifconfig
network.route = ip route

[apache]
apache.start = /usr/local/apache/bin/apachectl start
apache.stop = /usr/local/apache/bin/apachectl stop
apache.restart = /usr/local/apache/bin/apachectl restart
apache.status = ps ax |grep httpd
apache.conf = cat /usr/local/apache/conf/httpd.conf
apache.conf.vhost = cat /usr/local/apache/conf/extra/httpd-vhosts.conf
apache.logs.now =
apache.logs.tail = 

[resin]
resin.start = /usr/local/resin/bin/httpd.sh start
resin.stop = /usr/local/resin/bin/httpd.sh stop
resin.restart = /usr/local/resin/bin/httpd.sh restart
resin.status = /usr/local/resin/bin/httpd.sh status
resin.conf = cat /usr/local/resin/conf/resin.conf

[www]
www.list = ls -1 /www
www.permission = find /www -type d -exec chmod 755 {} \; find /www -type f -exec chmod 644 {} \;
www.permission.777 = chmod 777 -R /www/*
lamp.status = ps ax |grep -E "mysqld|httpd|resin"

[samba]
samba.start = /etc/init.d/smb start
samba.stop = /etc/init.d/smb stop
samba.restart = /etc/init.d/smb restart
samba.status = /etc/init.d/smb status

[mysql]
mysql.start = /etc/init.d/mysql start
mysql.stop = /etc/init.d/mysql stop
mysql.restart = /etc/init.d/mysql restart

[memcache]
memcache.start = /etc/init.d/memcache start
memcache.stop = /etc/init.d/memcache stop
memcache.restart = /etc/init.d/memcache restart

[vsftpd]
vsftpd.start = /etc/init.d/vsftpd start
vsftpd.stop = /etc/init.d/vsftpd stop
vsftpd.restart = /etc/init.d/vsftpd restart
vsftpd.status = /etc/init.d/vsftpd status

4. init.d 脚本

Linux 所有守护进程都是用init.d下面的脚本来管理

当人你也可以直接运行命令:

nodekeeper --daemon --host localhost --port 7800
		

但这样只能算是一个半成品,也不够专业,我们写的是linux运用程序,必须遵循Linux规范,所有要实现一个init.d脚本

$ cat nodekeeper
#! /bin/sh

### BEGIN INIT INFO
# Provides:          nodekeeper
# Required-Start:    $local_fs $remote_fs $network $syslog
# Required-Stop:     $local_fs $remote_fs $network $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts the nodekeeper web server
# Description:       starts nodekeeper using start-stop-daemon
### END INIT INFO

PATH=/srv/nodekeeper/bin:$PATH
DAEMON=/srv/nodekeeper/bin/nodekeeper
NAME=nodekeeper
DESC=nodekeeper
BASEDIR="/srv/nodekeeper"
HOST=$(ifconfig  | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f2 | awk '{ print $1}'|head -n 1)
PORT=7800
CONFIG=$BASEDIR/etc/$NAME.cfg
LOGFILE=$BASEDIR/log/$NAME.log
PIDFILE=$BASEDIR/run/$NAME.pid
PIDFILE=/var/run/$NAME.pid
PROTOCOL=$BASEDIR/etc/protocol.cfg

DAEMON_OPTS="--daemon --host $HOST --port $PORT --config=$CONFIG --protocol=$PROTOCOL --pidfile=$PIDFILE --logfile=$LOGFILE"

test -x $DAEMON || exit 0

# Include nodekeeper defaults if available
if [ -f /etc/default/nodekeeper ] ; then
	. /etc/default/nodekeeper
fi

set -e

. /lib/lsb/init-functions

#test_nodekeeper_config() {
#  if $DAEMON -t $DAEMON_OPTS >/dev/null 2>&1
#  then
#    return 0
#  else
#    $DAEMON -t $DAEMON_OPTS
#    return $?
#  fi
#}

case "$1" in
  start)
	echo -n "Starting $DESC: "
	start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \
		--exec $DAEMON -- $DAEMON_OPTS || true
	echo "$NAME."
	;;
  stop)
	echo -n "Stopping $DESC: "
	start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \
		--exec $DAEMON || true
	echo "$NAME."
	;;
  restart|force-reload)
	echo -n "Restarting $DESC: "
	start-stop-daemon --stop --quiet --pidfile \
		/var/run/$NAME.pid --exec $DAEMON || true
	sleep 1

	start-stop-daemon --start --quiet --pidfile \
		/var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS || true
	echo "$NAME."
	;;
  reload)
        echo -n "Reloading $DESC configuration: "

        start-stop-daemon --stop --signal HUP --quiet --pidfile /var/run/$NAME.pid \
            --exec $DAEMON || true
        echo "$NAME."
        ;;
  configtest)
        echo -n "Testing $DESC configuration: "
        if test_nodekeeper_config
        then
          echo "$NAME."
        else
          exit $?
        fi
        ;;
  status)
	status_of_proc -p /var/run/$NAME.pid "$DAEMON" nodekeeper && exit 0 || exit $?
	;;
  *)
	echo "Usage: $NAME {start|stop|restart|reload|force-reload|status|configtest}" >&2
	exit 1
	;;
esac

exit 0

我们将使用DAEMON_OPTS变量,提供所有需要的参数

DAEMON_OPTS="--daemon --host $HOST --port $PORT --config=$CONFIG --protocol=$PROTOCOL --pidfile=$PIDFILE --logfile=$LOGFILE"
		

4.1. start/stop

/etc/init.d/nodekeeper start
/etc/init.d/nodekeeper stop
			

4.2. service start/stop

service nodekeeper start
service nodekeeper stop
时间: 2024-12-04 23:12:50

Linux 应用程序开发入门的相关文章

《嵌入式 Linux应用程序开发标准教程(第2版)》——导读

前 言 嵌入式 Linux应用程序开发标准教程(第2版) 第2版说明 本书第1版<嵌入式Linux应用程序开发详解>自2006年7月出版以来,受到了广大读者的一致好评,已经多次印刷,累计销量18000册.许多高等院校.职业学校和培训机构也将本书作为嵌入式专业的教材.许多读者提出了宝贵的意见和中肯的建议. 第2版图书在第1版基础上做了以下修订. 增加PPT教学课件:本书第2版增加了PPT教学课件,方便老师教学使用. 赠送嵌入式专家授课视频:本书第2版免费赠送超值的嵌入式教学视频,所讲内容均为嵌入

《微信小程序开发入门精要》——第1章,第1.1节什么是微信小程序

第1章 微信小程序入门微信小程序开发入门精要微信小程序是腾讯在2016年9月推出的一种新型的微信扩展.尽管目前还没有正式开发,但依然受到了非常多的关注.这主要是由于腾讯的影响力,以及微信在国内拥有的庞大的用户群体.在2017年1月9日,腾讯已经正式上线了小程序,这意味着任何人都可以在手机微信中使用小程序.由于目前小程序的数量还不多,所以现在进入小程序开发领域,可能会赶上小程序的第一拨红利.OK,废话少说,从本章开始,让我们深入了解微信小程序的原理以及详细的开发过程. 本章要点什么是微信小程序注册

MSDN Webcast:ASP.NET MVC2程序开发入门到精通系列课程

课程讲师:苏鹏 MSDN特邀讲师北京工业大学软件工程硕士,微软最有价值专家(ASP.NET MVP),微软MSDN特约讲师.曾于微软亚洲工程院MSN组工作,现任中国网通四分公司技术支持与项目部开发经理.具有多年电信系统与OA系统实施经验. 课程下载: ASP.NET MVC2程序开发入门到精通系列课程(1):MVC架构概述 ASP.NET MVC2程序开发入门到精通系列课程(2):MVC范例分享 ASP.NET MVC2程序开发入门到精通系列课程(3):MVC中的View实现技巧(上) ASP.

《嵌入式 Linux应用程序开发标准教程(第2版)》——1.1 嵌入式Linux基础

1.1 嵌入式Linux基础 嵌入式 Linux应用程序开发标准教程(第2版) 自由开源软件在嵌入式应用上受到青睐,Linux日益成为主流的嵌入式操作系统之一.随着MOTOROLA手机A760.IBM智能型手表WatchPad.SharpPDA Zaurus等一款款高性能"智能数码产品"的出现,以及Motorola.Samsung.MontaVista.Philips.Nokia.IBM.SUN等众多国际顶级巨头的加入,嵌入式Linux的队伍越来越庞大了.目前,国外不少大学.研究机构和

《嵌入式 Linux应用程序开发标准教程(第2版)》——2.2 Linux启动过程详解

2.2 Linux启动过程详解 嵌入式 Linux应用程序开发标准教程(第2版) 在了解了Linux的常见命令之后,下面详细讲解Linux的启动过程.Linux的启动过程包含了Linux工作原理的精髓,而且在嵌入式开发过程中非常需要这方面的知识. 2.2.1 概述 用户开机启动Linux过程如下: (1)当用户打开PC(intel CPU)的电源时,CPU将自动进入实模式,并从地址0xFFFF0000开始自动执行程序代码,这个地址通常是ROM-BIOS中的地址.这时BIOS进行开机自检,并按BI

微信小程序开发入门教程

在这篇微信小程序开发教程中,我们将向你介绍快速试用和体验微信小程序开发工具和官方示例Demo. 本系列教程将引导你完成如下任务: 下载微信web开发者工具和小程序官方Demo. 添加小程序示例Demo到项目 体验小程序常用组件及接口   第一部分 下载开发者工具和官方Demo   微信小程序开发者工具 为了帮助开发者简单和高效地开发微信小程序,微信官方推出了全新的微信小程序开发者工具,该工具集成了开发调试.代码编辑及程序发布等功能. 下载地址为  windows 64 . windows 32 

《嵌入式 Linux应用程序开发标准教程(第2版)》——1.3 Linux文件及文件系统

1.3 Linux文件及文件系统 嵌入式 Linux应用程序开发标准教程(第2版) 在安装完Linux之后,下面先对Linux中一些非常重要的概念做一些介绍,以便进一步学习使用Linux. 1.3.1 文件类型及文件属性 1.文件类型 Linux中的文件类型与Windows有显著的区别,其中最显著的区别在于Linux对目录和设备都当作文件来进行处理,这样就简化了对各种不同类型设备的处理,提高了效率.Linux中主要的文件类型分为4种:普通文件.目录文件.链接文件和设备文件. (1)普通文件. 普

《嵌入式 Linux应用程序开发标准教程(第2版)》——1.4 实验内容——安装Linux操作系统

1.4 实验内容--安装Linux操作系统 嵌入式 Linux应用程序开发标准教程(第2版) 1.实验目的 读者通过亲自动手安装Linux操作系统,对Linux有个初步的认识,并且加深对Linux中的基本概念的理解,熟悉Linux文件系统目录结构. 2.实验内容 安装Linux(Red Hat Enterprise 4 AS版本)操作系统,查看Linux的目录结构. 3.实验步骤 (1)磁盘规划. 在这一步骤中,需要留出最好有5GB以上的空间来安装Linux系统. (2)下载Linux版本. 可

《嵌入式 Linux应用程序开发标准教程(第2版)》——1.5 本章小结

1.5 本章小结 嵌入式 Linux应用程序开发标准教程(第2版) 本章首先介绍了Linux的历史.嵌入式Linux操作系统的优势.Linux不同发行版本的区别以及如何学习Linux.在这里要着重掌握的是Linux内核与GNU的关系,了解Linux版本号的规律,同时还要了解Linux多硬件平台支持.低开发成本等优越性. 本章接着介绍了如何安装Linux,这里最关键的一步是分区.希望读者能很好地掌握主分区.扩展分区的概念.Linux文件系统与Windows文件系统的区别以及Linux中"挂载&qu