day32——类的属性总结、类的方法总结、rc脚本(类的定义与脚本的结构、start方法、stop和status方法、以daemon方式启动)

类的属性-总结
    ● 类属性,也是共有属性
    ● 类的私有属性
     ● 对象的共有属性
     ● 对象的私有属性
     ● 内置属性
     ● 函数的局部变量
     ● 全局变量
    例子:
    首先定义一个类MyClass,然后在类里面把这些所有的属性都给写里(所有属性都写给它),类的属性也是类的公有属性,__var2为类的私有属性,接下来去定义一个方法,方法名为func1,在这里面也去定义一些属性,在这里面定义属性用self,叫var3,把它定义到方法里了,所以叫对象的公有属性,var4是对象的私有属性,再定义一个,这次不加self,不加self表示函数的函数变量,让脚本支持中文需要在前面写上#coding:utf8,接下来去实例化一个对象,通过对象去访问这些属性,看哪些属性能访问哪些属性还能访问,首先看下访问类属性看是否可以(通过对象来访问,这是公有属性),打印结果是var1可以访问,通过对象来访问私有属性__var2,
    这种方法访问不了,
    如果想访问一个私有属性的话可以通过类名前面加上下划线来访问。在外部可以通过这种方法来访问,但不建议这么访问(只是为了测试一下),
    再访问对象的公有属性,看能不能访问,通过对象mc访问不了,提示没有这个属性,这是为什么呢?在访问之前需要执行一下这个方法,因为这个方法没有执行,没有执行意味着里面的这些属性或者变量(self.var3、self.__var4、var5)都没有,所以说访问不了。
    执行完mc.func1()方法之后就可以了,如果想访问对象里面的属性时需要先执行一下这个方法或者说调用一下这个方法才能访问func1这里面的属性,现在访问的是公有属性没有问题,那能不能通过类来访问呢?一会再通过类去访问。
    那能不能访问其他的呢?公有属性没有问题了,那私有属性呢?访问对象的私有属性,看来在类外面访问是不行的,
    那var5呢?var5是函数的局部变量,前面没有self,通过这种访问可不可以访问呢?也不行,它把它当成类的属性是没有的,那再实例化一个mc1,再得到一个对象,现在是通过mc能访问对象的属性var3,那能不能通过mc1访问var3呢?看来是访问不了,提示没有这个属性,那为什么mc就能访问呢?因为这个mc对象调用的是func1这个方法,而这个mc1没有去调用,没有调用就意味着没有执行这个func1方法里面的语句,没有执行这些语句意味着就不能访问里面的这些变量,现在知道为什么叫做对象的属性了,我们是通过对象来访问的,那么哪个对象在调用了这个方法那么这个对象就可以访问方法里面的属性,那么mc1没有调用这个func1方法意味着不能访问这个方法func1里面的属性,有点饶。
    再总结一下,像类的公有属性可以通过对象来访问,那么类的私有属性也可以通过对象来访问(通过一种特殊的方法),那么对象的公有属性呢通过对象也可以去访问,前提呢是这个对象要调用一下这个方法,那么对象的私有属性呢通过对象是不能访问(就是在类的外面通过对象不可以去访问),那么函数的局部变量呢在类的外面通过对象也不可以访问,下面看下通过类是否可以访问这些东西呢?
 
    先看下var1,类是没问题的(访问公有属性没有问题),
    那能不能通过类访问私有属性呢?是不可以的,
    那通过类能不能访问对象的公有属性呢?不可以,刚才通过对象也不可以访问,前提要把它给实例化一下,通过对象去访问一下这个func1方法,访问之后再通过类看能否访问方法里面的对象公有属性,也不行,不能访问,也就是说对象的属性只能通过对象来访问
 
    对象的属性和类的属性的区别就是定义的位置不一样,对象的属性是定义在方法里的,而类的属性是定义在方法外,当然通过类也不可以访问方法里面所有的属性,不管是公有的还是私有的还有局部变量都不可以访问,像var1、__var2、var3、__var4这些属性能不能在类的内部被访问呢(刚才测试是在类的外部去访问)?先测试var1和__var2这两个,这两个属性是没有问题,不管是公有的还是私有的都可以在内部被访问
    那么这个func1方法呢?在func2里面去调用一下,是不可以的,在内部也不可以,在内部为什么不可以呢?其实可以让它可以去访问的,我们先把这个func1函数(方法)调用一下,调用完之后就可以访问了,
    调用完之后这些var3、var4、var5这些值在内存当中都有,有了之后通过func2去访问了。那么这是通过访问对象的公有属性,那能不能访问对象的私有属性呢?当然前提是要先执行这个func1,因为这个属性是在func1里面定义的,
    最后也是可以访问的
     
    那能不能访问var5呢?var5是函数的局部变量,在这个func1函数里面是一定可以被访问到的,当然对象的私有属性(var4)在这个方法func1里也能访问到
    先把mc.func2()给注释掉,在def func1(self):里面去调用,结果显示对象的私有属性和函数的局部变量这两个都是可以访问到的,因为是在自己的方法里面定义的所以在自己的方法里面一定能够访问,那么在其他的方法里面可以不可以被访问到呢
    在func2里面去调用一下func1里面的叫做私有属性,也是可以访问的
    那么能不能访问局部变量呢?var5在func1是可以被访问到的,那么在func2是不能被访问的,这跟正常函数是一样的,就是在一个函数里面定义的变量在另外一个定义的函数里面是不能被访问的,除非把它变量为全局变量,NameError: global name 'var5' is not defined它把var5当成一个全局变量未被定义,
    可以在前面定义一个全局变量,全局变量是在函数的外面定义的
    有7种变量:全局变量、函数的局部变量、类属性(也叫类的公有属性)、类的私有属性、对象的公有属性、对象的私有属性,还有一个类的内置属性(__dict__),打印出来的是一个字典,打印的是func1里面的,因为var5是局部变量,而局部变量没有包括在内置属性里(内置属性没有它的值,只有对象的公有属性还有对象的私有属性),
    内置属性呢也可以通过类来调用,而通过类来调用的值就有很多了,
    类属性就表示只有类能调用的,只有公有属性类能调用,
 
类的方法总结
    ● 公有方法
    ● 私有方法
     ● 类方法
     ● 静态方法
     ● 内置方法
    先定义一个类MyClass,定义一个name属性,把这个属性给打印出来,然后再打印一个一句话"我是公有方法",在这里面一共定义了四种方法,分别去调用一下,看这些方法可以在什么地方可以调用。先进行实例化一下,
    先去调用func1,报错,需要支持中文。可以调用
    通过这个对象能否调用私有方法呢?不能调用,私有方法只能在内部去调用,
    比如在func1里面去调用,因为func1它是一个公有方法,可以通过调用func1来间接地调用这个__func2私有方法,私有方法在类的内部可以使用。
    类方法顾名思义就是通过类来调用的。它说这个不能作为MyClass作为参数来调用,那么怎么去弄呢?之前记得有过装饰器,可以在方法上面加个装饰器,有了它的修饰呢就表示这个方法可以被类来调用,
    那么静态方法是否可以被调用呢?静态方法其实也是通过类来调用的,看能否通过MyClass去调用一下,跟调用动态方法的提示差不多,也需要加上装饰器,但是在定义的时候不能加上self了
    提示23行全局变量'self'没有被定义,把这个self.name认为是全局变量了,在这里面要打印一下那个属性name,在这里面就不能通过self了,因为在定义这个staticFun():静态方法时括号里面没有self(不能加self),那么这个.name位置引用属性必须通过类来引用,
    现在这四个方法都可以调用了,func1是一个普通的公有方法,私有方法就是前面多了两个下划线,公有方法可以在类的内部和外部来调用,而私有方法只能在类的内部来调用。
    类方法有两个,一个是动态的叫类方法,一个叫静态的,叫静态方法,这两个方法可以通过类来调用,前提是要加个装饰器或者通过函数来修饰(就是通过函数来处理一下),加装饰器是最方便的,@classmethod是类方法的修饰器,它只能对下面的函数起作用,@staticmethod是静态的装饰器,修饰下面staticFun()函数的,静态方法在定义的时候不能有self这个参数,那么想使用这个类里面的属性要通过类的名字来调用而不能通过self来调用(不认识self是什么)。
    还有一种方法叫内置方法,这是系统自带的。__init__为构造函数,直接去调用func1。打印出两个私有,主要是有self.__func2()这一行,给注释掉,因为在func1里面又调用了一次func2,所以打印结果有两个私有。
    同样的也可以把刚才的类方法和静态方法写到__init__构造函数里,静态方法和类方法不仅可以通过类来调用还可以通过对象来调用,最后一行MyClass.staticFun()就不需要写了,因为这个构造函数也叫内置函数是在类实例化的时候自动会被执行,mc = MyClass()这是类实例化,那么只要实例化了__init__下面的四个函数都会被调用。
 
    我们学习了Python的面向对象,我们也知道了怎么去创建类,那么在类里面我们也可以去创建一些属性及一些方法,而这个属性又分为类的公有属性和私有属性,以及对象里也可以有共有属性以及私有属性甚至还可以有内置属性,方法也是一样有一些公有方法、私有方法还有一些内置方法。写一个关于类的实际例子,关于管理服务的例子,启动脚本,就像有的公司去开发一个程序之后呢我们要把这个程序执行一下,最简单的执行方式就是点斜杠文件就执行了,如果想停止的话找到pid直接kill一下就OK了,但是这种呢不是很友好的方法,系统当中有很多这样的启动脚本可以借鉴一下写一个Python版的启动脚本从而管理我们的这些服务,我们以memcached为例子写这样一个启动脚本,这个软件在镜像文件里有,直接安装就可以了,装好之后会有一个启动脚本/etc/init.d/memcached,可以通过这个脚本去启动一下,通常是/etc/init.d/memcached status、start、stop这样来管理服务的,可以看下这个脚本vim /etc/init.d/memcached,在这里面执行了. /etc/init.d/functions这个文件,好像每个启动脚本里面都会执行. /etc/init.d/functions这个文件,像下面PORT=1121、USER=memcached是定义一些变量(有端口号、用户名、最大连接数、CACHESIZE和OPTIONS),if [ -f /etc/sysconfig/memcached ];then是判断有没有这个文件,如果有的话执行一下,其实就这个文件. /etc/sysconfig/memcached里的内容跟上面定义的PORT内容一样,CACHESIZE单位是M,pidfile定义的路径,如果这个服务启动之后会产生一个这样的.pid文件,这个文件会记录着PID,在这里面定义一个start的函数,start函数最主要就是把存放PID的目录权限给改成memcached,以及这个执行程序在这daemon --pidfile ${pidfile} memcached -d -p $PORT -u $USER  -m $CACHESIZE -c $MAXCONN -P ${pidfile} $OPTIONS,-d表示以daemon的方式来运行的,-p表示端口号,-u表示用哪个用户来启动的,-m是表示用多大的内存,-c是最大连接数,-P指定pidfile,stop就是把这个/usr/bin/memcached的PID给kill掉,接下来rm -f ${lockfile} ${pidfile}就是把这个pidfile给rm掉,restart就比较简单,就是先stop再start,最后定义一个条件,当这个脚本判断第一个参数,如果第一个参数是start的话调用这个start函数,如果是stop则调用stop函数,是status会有status -p ${pidfile} memcached RETVAL=$?这样的输出。
    我们可以根据这个脚本呢写一个Python版的。
    我们可能还不知道用哪些模块,那没关系可以先定义一个类,等用的时候再import,这个类的类名叫Process(new_style方式),可以用'''memcached rc script '''注释一下(三个引号表示注释),接下来去定义一个构造函数,那么在类里面定义这个方法的时候一定要有一个参数self,然后再传几个其他的参数,在把这个类实例化的时候呢要传几个参数进来,而传的参数就可以通过这个__init__这个函数在这里面来定义,那么有一个name(name这个参数就表示这个程序的名字)、progran(表示这个程序的执行文件所在的路径)、args(就表示这个执行文件后面加一些什么参数,如加-u或-p)、workdir(就是存放PID的那个目录),在这里面有四个参数,分别通过这些属性或叫变量去接收一下,self.name加self表示它是一个类的属性,self就表示这是一个类的属性。那么这个构造函数呢在这里已经创建完了,其实就是在类实例化的时候要传这四个name,program,args,workdir参数。
    再定义一个方法,有一个def start(self):,先把结构给写出来,还有def stop(self):,在这里面别忘了括号里面要加上self,因为这是方法,还有def restart(self):,def restart(self):其实就是调用stop,如果想调用stop这个方法时要加self,因为它属性类里面的方法,不是函数,如果是函数是没有后面括号里面的self的,restart就是先self.stop()完了之后再self.start(),还有一个叫def status(self):,那么这几个主要的先把这结构给写出来,这是类里面的方法,
    接下来去定义一个函数,这里把def main()定义到类的外面了,定义到类的外面它就不是类里面的方法而是一个函数,那么在这里面这个脚本后面要接收一个参数,而这个参数就是start、stop或者是restart,我们先来个异常,就表示如果呢这个脚本后面没有带参数的话会是什么样的(会给出一个提示),sys.argv[1]就表示这个脚本后面带的第一个参数,except是抓异常,如果有异常的话怎么去解决,这里面先知道怎么写,后面专门有讲异常的视频,如果这个脚本后面没有参数的话会有一个这样的提示print "Option error",然后就退出了(没有参数就直接退出了),在这时候就需要在前面导入一个sys模块(import sys)
    结构就是上图这个结构,在这里面还需要再加上def __init(self):,初始化的意思,前面加一个下划线,_init不是内置方法,它就是一个普通的方法(如果是两个下划线那就是私有方法,如果前后有两个下划线那属性内置方法,这里面有一个下划线就是一个普通的方法),_init(self):就是判断这个目录有没有,如果没有的话去创建一下,这个结构就是这样的,可能在写的过程当中呢还会创建一些方法或一些函数,到时候再去写。
    假如前面的方法都已经都写好了,那么怎么去调用呢?如果想调用这些方法的话需要先实例化一下(把类实例化),实例化产生一个对象,对象叫pm,但是定义的时候有一个构造函数__init__,它里面有四个参数,那么我们在实例化的时候要传四个参数过来,第一个参数name叫'memcached',第二个参数prog,prog就是程序的名字(用which memcached查看一下),第三个参数args是启动时用什么参数,-u是用哪个用户启动,也可以用-d参数,-p端口号,默认是11211,-c是连接数,-m,第四个参数wordir等于'/var/tmp/memcached'这个路径,在pm = Process()括号里面就可以这样来写了,name = name,program = prog,args = args,workdir = wd,这就是类实例化,实例化传了四个参数过来,当然这个name也可以不用这么来写可以按照顺序写就可以了,把这四个值往里面(name = 等号右边)一写就可以了,跟定义时的顺序要一样,在这里面如果顺序不一样的话需要指定一下。调用完之后呢后面应该这样来写了,判断了,看这个cmd等于什么,如果等于'start'就调用start方法(pm.start()),如果等于stop则调用stop方法,如果等于restart则调用restart方法,如果等于status则调用status方法,还有一个(try表示异常就是没有参数的时候出现这个提示print "Option error"),如果参数分别是start、stop、restart、status这些时调用不同的方法,而这些方法就是上面四个最基本的start、stop、restart和status,假如脚本后面都不是这四个,可能是其他的,在这里面可以定义一个这样的方法--帮助,帮助可以打印一个消息说请使用脚本的名字后面加上start、stop、restart或status这样的提示,当然如果这里有help方法呢需要在最后去定义一个。类函数定义完之后呢去调用一下。关键是前面几个函数怎么去实现一下。
 
 
接下来就去实现这些方法,先看下start方法,其实start就是启动服务,如果在命令行启动的话就是memcached -u nobody -p 11211 -c 1024 -m 64,脚本当中有-d先不加,然后看下进程:ps -ef|grep mem,进程是58926,用户是nobody,父进程是55470,父进程就是当前启动的shell,它就是个bash,
    start就是执行这些命令,这些命令会有一个PID,然后把这个PID写到一个文件里,脚本里已经定义了workdir,而这个workdir就是'/var/tmp/memcached'这个目录,系统默认是'/var/memcached'目录,我们定义另外一个目录,所以说在这个初始化函数里面把这个目录给它创建好,这个目录是在'''/var/tmp/memcached'''下,先判断一下这个目录是否存在,如果这个目录不存在,这个目录就是self.workdir,在这里面有一个类的属性,在这个方法里面直接来使用,用时直接在前面加个self然后是点.workdir,干什么呢?去创建这个目录,创建目录有一个os.mkdir()这个方法,创建完之后再进到这个目录下(有os.chdir()方法,相当于是cd命令),那么初始化方法呢它只做这件事,就是判断目录有没有,如果没有的话创建并能cd到这个目录下
    再来看这个start方法,start方法就像刚才说的一样,先把这个命令给组建好,要执行这个命令,这个命令就是memcached,self.program(就是在实例化的时候传一个参数进来,)其实我们现在写的是memcached,当然也可以换其他的程序,换其他程序只要在脚本当中实例化的时候把prog = '/usr/bin/memcached'这个给改一下就可以,其他地方都不用改,cmd=这个程序+什么呢?应该加上一些选项,选项就是args呗,先把命令行组建一下,执行命令就是在Python里面调用shell命令有很多种方法,在后面课程当中会有详细介绍,那么在这里面我们先使用最常用的是Popen方法,如果使用得加载一个模块(还需要加载os模块和subproe),在这我们会用就行。如果在Python执行shell命令可以这样:p = Popen(cmd, stdout=PIPE, stdout=PIPE,shell=True),PIPE是管理的意思,把这个标准输出写到一个管道里,管道就类似于一个临时文件一样,错误输出就先不写了。
    可以先在python里面先演示一下,执行完之后先到后台看一下,ps -ef|grep memcached有这个进程了,那么就可以把这个进程号写到这个文件里就可以了。上面是执行这个命令。
    执行完命令之后呢(也就是memcached已经启动了)有一个进程PID,进程PID是一个数值类型的,要把它写到一个文件里,那么为了实现写到一个文件里,在上面需要定义一些方法, 先定义一个方法pidFile(就是一个PID文件),PID文件应该是'''/var/tmp/memcached/memcached.pid'''这个文件,在这里面PID范围呢直接return返回就行了,在工作目录workdir下,下面有个pid文件。
    再定义一个_writhPid方法, 先判断一下PID有没有,这个方法是专门把PID写到文件里,PID是在哪里出来呢?是在def start(self):下面有个p.pid出来的,可以通过Popen产生一个对象,它有一个p.pid这样的属性,这个属性可以得到PID,但是如果这么写的话只能在start方法里面能够得到,如果想要在_writhPid里也能得到PID怎么办呢?应该在def start(self):里这么来写:,变成一个类的属性,然后在def _writhPid(self):里面就可以直接使用了,如果PID有值的话打开这个文件(就是打开__pidFile这个文件,__pidFile这个方法的返回就是一个文件嘛,就是'''/var/tmp/memcached/memcached.pid'''这个文件),在这里想调用上面的__pidFile方法,跟调用属性一样加self,以w的方式打开,然后就是往里面写了,就是往里面写self.pid,但是它是一个数值的(它没有引号),需要把它变量字符串。在这PID得到了,得到之后就直接写入到文件呗,写文件应该在def start(self):里调用self._writhPid()方法。其实调用方法跟调用函数一样,我们不写成类的形式都是写成函数的形式就可以直接调用函数了,只不过在类里面调用方法要加上个self,最好呢来个输出:print "%s start Sucessful" % self.name表示这个程序已经启动成功。
    先测试一下start有无启动。需要先停memcached,
    退出IPython这个进程[memcached] <defunct>就会没有了
    提示第28行缩进错误,
    其实我们在def stop(self):定义函数,函数里面没有东西,需要用pass来占位(可以不用写代码块,pass是什么都不用做)
 
    如果什么都不写的话会有个Option error,这个是那个异常里面的提示,因为没有参数的时候会出现这个错误
    会报一个错误,端口被占用,已启动memcached进程
    下面这个错是因为定义的def __pidFile(self):有两个下划线,而with open(self._pidFile(), 'w') as fd:这里的_pidFile却只有一个下划线导致的
 
    报一个错误,No such file or directory: '/var/tmp/memcached/memcached.pid'说这个文件没有,为什么PID文件没有产生呢?我们可以看下这个脚本,这个脚本在执行start时,这条命令cmd = self.program + ' ' + self.args是可以执行的(在IPython执行过这条命令),而且进程是有的,但是没有产生PID文件,那么产生PID文件是在上面def _pidFile(self):和def _writhPid(self):定义的这两个函数,return os.path.join(self.workdir, "%s.pid" % self.name)这个是先定义一下pid文件,_writhPid函数是把pid写到文件里,但写的时候没有这个文件,这是为什么呢?由于这个目录/var/tmp/memcached/不存在,那为什么刚才存在呢?因为这是之前就有的,为什么没有呢?这个目录是怎么来的呢?这个目录其实是通过初始化def __init__(self,name,program,args,workdir):这个方法来创建的,但是在这里面只是定义了初始化的方法并没有去调用,所以是不是应该在执行start的时候去把这个方法调用一下是吧?在def start(self):下面写上self._init(),调用一下这个方法这个目录就有了,有了才能把pdi文件写到这个目录里去,
    这回就显示成功了,pid文件也有了,第一次老师执行过这个脚本所以这个/var/tmp/memcached/目录是存在的。当把这个目录删除之后由于没有调用__init__这个方法所以有刚才没有memcached目录的错误提示。
    为了实现这个start方法又额外去创建了两个方法,一个是_pidFile,_pidFile其实就是返回一个文件路径,一个是_writhPid,_writhPid其实就是把pid写到文件里,在这里面要注意self.pid:,它是在start里面定义的,start里面定义的self.pid是一个属性,如果这个start下面的self.pid位置使用函数的局部变量在_writhPid就不能这么使用了,所以属性的好处就是定义完之后呢可以在各个方法里面去调用。其实把_pidFile和_writhPid都写到start是可以也没总是的,但是我们在写这个程序的时候,最好比如说一件工作或一个功能最好由一个方法或者一个函数来做,这样程序看起来更清楚一些,不管是可读性还是调试条理更清楚,
 
    现在start这部分代码没总是了,接下来怎么实现stop给它停掉,其实呢在rc脚本停掉就是找到pdi把它kill掉,那么在这里面怎么找pid呢?那能否通过pid文件来找pid呢?是可以的(文件里面的内容是pid),但是不建议大家这么写,虽然我们每次启动都会更新这个文件,但是这么写呢不是很保险,比如说这个pid文件没了呢,就不能通过这个pid文件查看pid了,其实最直接的办法就是查看这个进程在不在,如果进程在的话找到这个进程的pid直接给kill掉,之后再判断pid文件存在的话把它rm删除就可以了,这就是stop,那么找进程所对应的pid呢,可以通过ps -ef来搜一下,但是之前有一个统计appace进程所占的内存,当时使用的是pidof命令,pidof memcached得到的就是pid(进程的pid),这种是最直接的办法,假如这个进程不存在则返回的是空,如果进程存在则返回的是进程的pid,
    直接在Ipython里面先执行一下,执行Popen可以把它放到列表里,2882这个返回的值就是PID,
    那么有了这个方法呢就可以把它写到脚本当中。需要先得到PID,也为得到PID需要再写个方法,也是写到列表里,写到列表里是比较安全的,那么命令的每一项呢是列表里面的每个元素。在IPython输出会有一个\n,需要去年\n,然后return一下pid变量,这个pid就是函数的局部变量,把它return一下,teturn pid。stop就是先调用一下_getPid方法,这样就得到了pid,得到pid后就kill一下,怎么kill呢?os模块有一个kill方法,括号前面是PID,后面是信号,正常的kill信号是15,这样就把它给kill掉了,然后用ps -ef|grep memcached没有进程号了,
    然后再判断一下,如果有pid的话os.kill掉,而这个pid是放到引号里面的说明是个字符串,需要用int转换成数值类型,os.kill(int(pid),15)这样就把它杀掉了,kill把这个进程杀掉了,那么进程的文件还在应该把这个文件也给删除掉,如果文件(pid文件存在则删除,上面写过这样的_pidFile方法直接调用就可以了,删除是os模块中的remove()方法,文件删除了以后print一下,说这个memcached已经被停掉了,
    stop完整之后是restart,restart就是调用stop和start这两个方法。
    接下来写status查看状态,那么状态怎么查看呢?其实跟刚才得到pid是一样的,如果有pid了说明它正在运行,如果得不到pdi呢就是没有运行,就这么来判断一下。如果pid有值的话就print说这个memcached is already running,否则"%s is not running" % self.name。status比较好判断,因为之前那些函数都实现过,方法也都实现过,
    python rc.memcached.py假如加入其它参数,应该调用def help(self)函数,help给出一个输出就可以了,输出怎么写呢?可以借鉴一下/etc/init.d/memcached脚本中的echo $"Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart|try-restart}",我们只写了前面四个,后面什么reload我们都没有,$0表示脚本的本身,在这里也可以通过字符串格式化来表示,__file__这么写是内置变量,它就表示脚本的本身,跟shell的$0是一样的,
    在这里面用了几个方法,这四个if cmd == 'start':、elif cmd == 'stop':、elif cmd == 'restart':和elif cmd == 'status':是最主要的,那么在实现这四个方法的时候又写了好几个其他的方法,如_pidFile,还有_writhPid,_getPid(这个方法是得到PID是什么),这里面还有一个__file__内置变量(双下划线),它跟shell的$0是一样的,还有我们会发现在print时都是使用字符串格式化,这样看下来程序更优美一些,
    我们再启动一下,它的父进程是1,虽然我们没有加-d选项,-d是daemon意思,没有加-d它的父进程也是1,其实这是由这个程序决定的,比如我们停止mamcached,我们用命令行重启一下,
    先查看tty,echo $$是脚本运行的当前进程ID号,3870是当前的bash,对应的是pst/2,
    在命令行把usr/bin/memcached -u nobody -p 11211 -c 1024 -m 64给启动一下,刚才启动的时候发现父进程是1,这样来启动:/usr/bin/memcached -u nobody -p 11211 -c 1024 -m 64 & 放到后台,放到后台会发现父进程是3870(bash的进程),子进程是4190(是memcached的进程)。现在把这个终端给退出(bash退出),bash这个进程是3870,退出之后这个memcached会退出吗?发现还会正常运行,然后父进程会变成1,由于刚才的进程是3870,它的父进程退出了,退出之后呢那么它就没有父进程了,它会被第一个进程init给接收了,它的父进程变成了init,这也是memcached这个程序自行决定的,我们不用daemon方式来启动也可以,它并不会说随着shell的退出而退出,那么当它的父进程退出之后它会被init接收,如果脚本直接启动的话会发现它的父进程就是1了。
 
 
关闭memcached,再start时会有一个提示,进程在运行,这个端口被占用,
    再次查看pid文件时里面的文件内容的pid变了,原来4343变成了4360,其实在第二次执行start时也是执行了memcached,当时也产生了一个进程,但是马上退出了,为什么退出了呢?因为memcached的sock被占用了,所以它就退出了,退出是退出了但是它会把这个PID又写到了pid文件里,算是一个脚本中的小bug,应该去判断一下,如果呢这个进程有的话就不运行了退出给个警告就ok了,别再执行一次了,因为一执行虽然在操作系统层面上这个进程不会执行成功但是它会写到pid文件中去,这样实际运行的pid和文件里面的pid两者就不一样了。 
    其实就在def start(self):这一块,就是说在不是执行这个模块下面的代码块需要先判断一下有没有进程,前面写过pid方法,只要对它做个判断就行了,如果有值的话print 说memcached正在运行,接下来就是sys.exit()退出,
    当再执行一次start时直接给出警告了,进程文件也没有变,
    看下vim /etc/init.d/memcached的启动脚本,这个脚本是以daemon的方式来运行的,什么叫daemon方式呢?就是在运行的时候加了个-d,我们前面的脚本是没有加-d选项的,没有加-d表示它的父进程是当前的shell,当然当前shell退出也不会影响memcached的运行,它的父进程会变成1,但是如果以-d的方式运行那么它的父进程会直接是1了。一般-d和-P是一块使用的,-P是来指定pidfile范围。脚本里面又执行了一下. /etc/sysconfig/memcached,这个文件的内容呢其实和/etc/init.d/memcached定义的变量是一样的,也就是说如果呢去更改/etc/sysconfig/memcached这个文件的内容(比如把USER改成nobody、CACHESIZE改变128),那么会覆盖etc/init.d/memcached文件里面定义的变量(PORT、USER、MAXCONN、CACHESIZE、OPTIONS),因为. /etc/sysconfig/memcached是脚本嘛,后面的执行了当然会覆盖前面的变量。如果这个文件. vim /etc/init.d/memcached没有动的话默认是按照/etc/sysconfig/memcached这个文件去设置,如果这个文件改动了会按照这个最新的设置去启动memcached,-p、-u、-m、-c都是引用/etc/init.d/memcached上面的变量,那么我们的python脚本是否也写成类似的形式呢?我们可以读这个文件,当然如果没有这个文件的话我们也会给一些默认值,就比如说判断这个文件,如果文件存在的话就会执行. /etc/sysconfig/memcached,如果文件不存在的话还会有一些默认的值,我们也可以这样去设置一些,让python脚本可以通过/etc/sysconfig/memcached文件去设置一些启动参数,然后再加上-d选项,让这个python脚本是通过后台运行的(就是以daemon方式运行),
    修改脚本让以daemon的方式运行,# cp rc.memcached.py rc.memcached1.py
    # vim rc.memcached1.py(原来脚本不是以daemon方式)
    def __init__(self,name,program,args,workdir):这些参数需要重新设定一下。
 
 
 
 
 
posted @ 2017-12-04 23:12  落后乞丐  阅读(56)  评论(0)    收藏  举报