日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux 应用程序开发入门

發(fā)布時間:2023/12/31 linux 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux 应用程序开发入门 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Linux 應用程序開發(fā)入門

Neo Chen?(netkiller)


<openunix@163.com>

版權 ? 2011, 2012 http://netkiller.github.com

摘要

我會實現(xiàn)一個守護進程,從這個程序你將了解,Linux 應用程序開發(fā)基本流程

我們將實現(xiàn)一個遠程shell的功能,可以通過tcp協(xié)議,運行遠程機器上的命令或shell腳本

通過這個命令可以實現(xiàn)批量操作,管理上千臺服務器。需要發(fā)揮你的想象力,靈活使用它。

寫這個腳本,我是為了替代SSH遠程操作,因為SSH不能控制運行命令,操作風險大,也不安全。

程序還不完善,還需要很多后續(xù)改進工作,比如通過SSL建立Socket鏈接,用戶認證,ACL訪問控制等等.

下面是我多年積累下來的經(jīng)驗總結,整理成文檔供大家參考:

?

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. 環(huán)境2. nodekeeper 主程序2.1. 幫助信息2.2. 參數(shù)處理2.3. 后臺運行2.4. 日志記錄2.5. 多線程3. 配置文件4. init.d 腳本4.1. start/stop4.2. service start/stop

1.?環(huán)境

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 Processclass Backend(asyncore.dispatcher):queue = []def __init__(self, host, port,config):asyncore.dispatcher.__init__(self)self.host = hostself.port = portself.config = configself.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):passdef 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 = resourceself.buffer = b''self.set_terminator(b"\r\n")self.logging = resource.loggingself.protocols = resource.protocolsself.sections = resource.sectionsself.host = self.sessions.hostdef handle_connect(self):# connection succeeded#self.logging.info('')passdef handle_expt(self):# connection failedself.close()def collect_incoming_data(self, data):"""Buffer the data"""#self.buffer.append(data)self.buffer = datadef 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] + ' ' + parameterscreen = 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 = Noneagreement = Nonedef __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.agreementdef 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.agreementdef main():daemon = Falsehost = 'localhost'port = 7800pidfile = ''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 = Trueelif o in ("-h", "--host"):host = aelif o in ("-p", "--port"):port = int(a)elif o in ("--basedir"):BASEDIR = aelif o in ("--pidfile"):pidfile = aelif o in ("--config"):cfgfile = aelif o in ("--protocol"):protocol = a elif o in ("--logfile"):logfile = aelse: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 parentsys.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 platformMandatory 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 7800nodekeeper -d -h localhost -p 7800See 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.?參數(shù)處理

getopt.getopt 實現(xiàn)Unix風格的命令參數(shù),例如:

nodekeeper --daemon --host localhost --port 7800--host localhost --port 7800 IP地址與端口參數(shù) --daemon 參數(shù)實現(xiàn)后臺運行

具體實現(xiàn)代碼

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 = Trueelif o in ("-h", "--host"):host = aelif o in ("-p", "--port"):port = int(a)elif o in ("--basedir"):BASEDIR = aelif o in ("--pidfile"):pidfile = aelif o in ("--config"):cfgfile = aelif o in ("--protocol"):protocol = a elif o in ("--logfile"):logfile = aelse:assert False, "unhandled option"except getopt.GetoptError as err:# print help information and exit:usage()sys.exit(2)

2.3.?后臺運行

--daemon 參數(shù)實現(xiàn)后臺運行,原理是首先通過os.fork()克隆一個進程,然后退出當前進程,克隆的新進程繼續(xù)運行

如果是Shell程序,你可使用“&”符號后臺運行,但作為一個應用程序,使用“&”顯得不專業(yè)。

具體實現(xiàn)的代碼如下

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

程序一旦進入后臺,當前進程即將關閉,所以你必須保存PID,為后面的推出程序操作使用,這里我們可以通過 --pidfile 指定一個pid文件

2.4.?日志記錄

程序一旦進入后臺,你只能通過ps,pstree, top 等命令查看狀態(tài),運行情況必須通過日志的形式,打印出來

具體實現(xiàn)代碼如下:

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 實現(xiàn)多線程

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

連接數(shù)限制

self.listen(10)

可以將這個參數(shù)提出來,然后通過命令行設置。

nodekeeper --daemon --maxconn 100 --host localhost --port 7800self.max_connect = maxconnself.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

但這樣只能算是一個半成品,也不夠專業(yè),我們寫的是linux運用程序,必須遵循Linux規(guī)范,所有要實現(xiàn)一個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 INFOPATH=/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.cfgDAEMON_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 fiset -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" instart)echo -n "Starting $DESC: "start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \--exec $DAEMON -- $DAEMON_OPTS || trueecho "$NAME.";;stop)echo -n "Stopping $DESC: "start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \--exec $DAEMON || trueecho "$NAME.";;restart|force-reload)echo -n "Restarting $DESC: "start-stop-daemon --stop --quiet --pidfile \/var/run/$NAME.pid --exec $DAEMON || truesleep 1start-stop-daemon --start --quiet --pidfile \/var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS || trueecho "$NAME.";;reload)echo -n "Reloading $DESC configuration: "start-stop-daemon --stop --signal HUP --quiet --pidfile /var/run/$NAME.pid \--exec $DAEMON || trueecho "$NAME.";;configtest)echo -n "Testing $DESC configuration: "if test_nodekeeper_configthenecho "$NAME."elseexit $?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}" >&2exit 1;; esacexit 0

我們將使用DAEMON_OPTS變量,提供所有需要的參數(shù)

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

總結

以上是生活随笔為你收集整理的Linux 应用程序开发入门的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。