一、difflib模块
文件差异对比模块
1.比较两个文件的不同.
import difflib
def read_content(filename):
with open(filename) as f:
return f.read()
content1 = read_content('dir/httpd.conf').splitlines()
content2 = read_content('dir/httpd_backup.conf').splitlines()
# 实例化对象
d = difflib.Differ()
res = list(d.compare(content1,content2))
from pprint import pprint as _pprint
print(_pprint(res))
print(''.join(res),end='')
2.以html页面显示两个文件的不同
import difflib
import sys
def read_content(filename):
with open(filename) as f:
return f.read()
def main():
if len(sys.argv) !=4:
print("""
Usage:
%s 配置文件名1 配置文件名2 html文件名
"""%(sys.argv[0]))
else:
file1 = sys.argv[1]
file2 = sys.argv[2]
htmlFileName = sys.argv[3]
content1 = read_content(file1).splitlines()
content2 = read_content(file2).splitlines()
d = difflib.HtmlDiff()
html_content= d.make_file(content1,content2)
with open(htmlFileName,'w') as f:
f.write(html_content)
print("写入%s成功" %(htmlFileName))
if __name__ == "__main__":
main()
二、OS模块
os
os.environ 一个dictionary 包含环境变量的映射关系
os.name 显示当前使用的平台
os.sep 显示当前平台下路径分隔符
os.linesep 给出当前平台使用的行终止符
os.remove('filename') 删除一个文件
os.rename("oldname","newname") 重命名文件
os.getcwd() 显示当前python脚本工作路径
os.chdir(dir) 改变当前目录,注意windows下用到转义
os.listdir('dirname') 返回指定目录下的所有文件和目录名
os.makedirs('dirname/dirname') 可生成多层递规目录
os.rmdir('dirname') 删除单级目录
os.getlogin() 得到用户登录名称
os.getenv(‘key’) 得到环境变量配置
os.putenv(‘key’) 设置环境变量
os.system() 运行shell命令,注意:这里是打开一个新的shell,运行命令,当命令结束后,关闭shell。
import os
print(os.environ)
print(os.access('/etc/passwd',os.R_OK))
print(os.access('/etc/passwd',os.W_OK))
print(os.access('/etc/passwd',os.X_OK))
filestat = os.stat('/etc/passwd') ## 文件状态
print(filestat,'\n',
type(filestat))
print(filestat.st_blocks)
print(filestat.st_gid)
print(filestat.st_uid)
print(filestat.st_mode)
print(filestat.st_ctime)
/usr/local/python3/bin/python3.6 /root/PycharmProjects/day12/01_常用模块.py
environ({'PATH': '/usr/lib64/qt-3.3/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/home/kiosk/.local/bin:/home/kiosk/bin', 'XAUTHORITY': '/root/.xauthSzTEJE', 'LC_MEASUREMENT': 'zh_CN.UTF-8', 'IMSETTINGS_MODULE': 'none', 'HISTCONTROL': 'ignoredups', 'XMODIFIERS': '@im=ibus', 'GDMSESSION': 'gnome-classic', 'LC_TIME': 'zh_CN.UTF-8', 'DBUS_SESSION_BUS_ADDRESS': 'unix:abstract=/tmp/dbus-BakeaW5IfG,guid=ee50c8c0688448752fe814095b20fce1', 'XDG_CURRENT_DESKTOP': 'GNOME-Classic:GNOME', 'MAIL': '/var/spool/mail/kiosk', 'SSH_AGENT_PID': '2700', 'LD_LIBRARY_PATH': '/opt/pycharm-community-2017.1.4/bin:', 'SESSION_MANAGER': 'local/unix:@/tmp/.ICE-unix/2493,unix/unix:/tmp/.ICE-unix/2493', 'USERNAME': 'kiosk', 'LC_PAPER': 'zh_CN.UTF-8', 'LOGNAME': 'kiosk', 'PWD': '/root/PycharmProjects/day12', 'PYCHARM_HOSTED': '1', 'WINDOWID': '35651591', 'PYTHONPATH': '/root/PycharmProjects/day07:/root/PycharmProjects', 'LESSOPEN': '||/usr/bin/lesspipe.sh %s', 'SHELL': '/bin/bash', 'QT_GRAPHICSSYSTEM_CHECKED': '1', 'QTINC': '/usr/lib64/qt-3.3/include', 'GNOME_DESKTOP_SESSION_ID': 'this-is-deprecated', 'IMSETTINGS_INTEGRATE_DESKTOP': 'yes', 'XDG_SESSION_DESKTOP': 'gnome-classic', 'LS_COLORS': 'rs=0:di=38;5;27:ln=38;5;51:mh=44;38;5;15:pi=40;38;5;11:so=38;5;13:do=38;5;5:bd=48;5;232;38;5;11:cd=48;5;232;38;5;3:or=48;5;232;38;5;9:mi=05;48;5;232;38;5;15:su=48;5;196;38;5;15:sg=48;5;11;38;5;16:ca=48;5;196;38;5;226:tw=48;5;10;38;5;16:ow=48;5;10;38;5;21:st=48;5;21;38;5;15:ex=38;5;34:*.tar=38;5;9:*.tgz=38;5;9:*.arc=38;5;9:*.arj=38;5;9:*.taz=38;5;9:*.lha=38;5;9:*.lz4=38;5;9:*.lzh=38;5;9:*.lzma=38;5;9:*.tlz=38;5;9:*.txz=38;5;9:*.tzo=38;5;9:*.t7z=38;5;9:*.zip=38;5;9:*.z=38;5;9:*.Z=38;5;9:*.dz=38;5;9:*.gz=38;5;9:*.lrz=38;5;9:*.lz=38;5;9:*.lzo=38;5;9:*.xz=38;5;9:*.bz2=38;5;9:*.bz=38;5;9:*.tbz=38;5;9:*.tbz2=38;5;9:*.tz=38;5;9:*.deb=38;5;9:*.rpm=38;5;9:*.jar=38;5;9:*.war=38;5;9:*.ear=38;5;9:*.sar=38;5;9:*.rar=38;5;9:*.alz=38;5;9:*.ace=38;5;9:*.zoo=38;5;9:*.cpio=38;5;9:*.7z=38;5;9:*.rz=38;5;9:*.cab=38;5;9:*.jpg=38;5;13:*.jpeg=38;5;13:*.gif=38;5;13:*.bmp=38;5;13:*.pbm=38;5;13:*.pgm=38;5;13:*.ppm=38;5;13:*.tga=38;5;13:*.xbm=38;5;13:*.xpm=38;5;13:*.tif=38;5;13:*.tiff=38;5;13:*.png=38;5;13:*.svg=38;5;13:*.svgz=38;5;13:*.mng=38;5;13:*.pcx=38;5;13:*.mov=38;5;13:*.mpg=38;5;13:*.mpeg=38;5;13:*.m2v=38;5;13:*.mkv=38;5;13:*.webm=38;5;13:*.ogm=38;5;13:*.mp4=38;5;13:*.m4v=38;5;13:*.mp4v=38;5;13:*.vob=38;5;13:*.qt=38;5;13:*.nuv=38;5;13:*.wmv=38;5;13:*.asf=38;5;13:*.rm=38;5;13:*.rmvb=38;5;13:*.flc=38;5;13:*.avi=38;5;13:*.fli=38;5;13:*.flv=38;5;13:*.gl=38;5;13:*.dl=38;5;13:*.xcf=38;5;13:*.xwd=38;5;13:*.yuv=38;5;13:*.cgm=38;5;13:*.emf=38;5;13:*.axv=38;5;13:*.anx=38;5;13:*.ogv=38;5;13:*.ogx=38;5;13:*.aac=38;5;45:*.au=38;5;45:*.flac=38;5;45:*.mid=38;5;45:*.midi=38;5;45:*.mka=38;5;45:*.mp3=38;5;45:*.mpc=38;5;45:*.ogg=38;5;45:*.ra=38;5;45:*.wav=38;5;45:*.axa=38;5;45:*.oga=38;5;45:*.spx=38;5;45:*.xspf=38;5;45:', 'SHLVL': '4', 'QT_PLUGIN_PATH': '/usr/lib64/kde4/plugins:/usr/lib/kde4/plugins', 'LC_MONETARY': 'zh_CN.UTF-8', 'QT_IM_MODULE': 'ibus', 'HISTSIZE': '1000', 'TERM': 'xterm-256color', 'XFILESEARCHPATH': '/usr/dt/app-defaults/%L/Dt', 'LANG': 'en_GB.utf8', 'XDG_SESSION_ID': '1', 'DISPLAY': ':0', '_': '/opt/pycharm-community-2017.1.4/jre64/bin/java', 'GDM_LANG': 'en_GB.utf8', 'PYTHONIOENCODING': 'UTF-8', 'DESKTOP_SESSION': 'gnome-classic', 'GPG_AGENT_INFO': '/run/user/1001/keyring/gpg:0:1', 'USER': 'kiosk', 'XDG_MENU_PREFIX': 'gnome-', 'WINDOWPATH': '1', 'VTE_VERSION': '3803', 'LC_NUMERIC': 'zh_CN.UTF-8', 'XDG_SEAT': 'seat0', 'SSH_AUTH_SOCK': '/run/user/1001/keyring/ssh', 'PYTHONUNBUFFERED': '1', 'HOSTNAME': 'foundation10.example.com', 'QTDIR': '/usr/lib64/qt-3.3', 'NLSPATH': '/usr/dt/lib/nls/msg/%L/%N.cat', 'GNOME_SHELL_SESSION_MODE': 'classic', 'KDEDIRS': '/usr', 'XDG_RUNTIME_DIR': '/run/user/1001', 'XDG_VTNR': '1', 'QTLIB': '/usr/lib64/qt-3.3/lib', 'HOME': '/root'})
True
True
False
os.stat_result(st_mode=33188, st_ino=138422790, st_dev=64768, st_nlink=1, st_uid=0, st_gid=0, st_size=3342, st_atime=1528888501, st_mtime=1523758264, st_ctime=1523758264)
'os.stat_result'>
8
0
0
33188
1523758264.3586972
os.path
os.path.abspath() 获取绝对路径os.path.abspath("1.txt") == os.path.join(os.getcwd(),"1.txt")
os.path.split() 用于分开一个目录名称中的目录部分和文件名称部分
os.pardir 表示当前平台下上一级目录的字符
os.path.join(path, name) 连接目录和文件名。
os.path.basename(path) 返回文件名
os.path.dirname(path) 返回文件路径
os.path.getctime("/root/1.txt") 返回1.txt的ctime(创建时间)时间戳
os.path.exists(os.getcwd()) 判断文件是否存在
os.path.isfile(os.getcwd()) 判断是否是文件名,1是0否
os.path.isdir('c:\Python\temp') 判断是否是目录,1是0否
os.path.islink('/home/111.sql') 是否是符号连接,windows下不可用
os.path.ismout(os.getcwd()) 是否是文件系统安装点,windows下不可用
os.path.samefile(os.getcwd(), '/home') 看看两个文件名是不是指的是同一个文件
os.walk() 能够把给定的目录下的所有目录和文件遍历出来
os.path.walk('/home/huaying', test_fun, "a.c") 遍历/home/huaying下所有子目录包括本目录,对于每个目录都会调用函数test_fun。
print(os.path.getsize('/etc/passwd'))
print(os.path.getmtime('/etc/passwd'))
/usr/local/python3/bin/python3.6 /root/PycharmProjects/day12/01_常用模块.py
3342
1523758264.3356972
dir(sys) dir()方法查看模块中可用的方法。注意:如果是在编辑器,一定要注意要事先声明代码的编码方式,否则中文会乱码。
sys.argv 实现从程序外部向程序传递参数
sys.exit([arg]) 程序中间的退出,arg=0为正常退出
sys.getdefaultencoding() 获取系统当前编码,一般默认为ascii
sys.setdefaultencoding() 设置系统默认编码,执行dir(sys)时不会看到这个方法,在解释器中执行不通过,可以先执行reload(sys), 再执行setdefaultencoding('utf8'),将系统编码设置为utf8
sys.getfilesystemencoding() 获取文件系统编码方式,Windows下返回'mbcs',mac下返回'utf-8'
sys.path 获取指定模块搜索路径的字符串集合,可以将写好的模块放在得到的某个路径下,就可以在程序中import时正确找到
sys.platform 获取当前系统平台
sys.stdin,sys.stdout,sys.stderr stdin,stdout,以及stderr变量包含与标准I/O流对应的流对象。如果需要更好地控制输出,而print不能满足要求,它们就是你所需要的。你也可以替换它们,重定向输出和输入到其它设备(device),或者以非标准的方式处理它们。
sys.modules 是一个全局字典,该字典是python启动后就加载在内存中。每当程序员导入新的模块,sys.modules将自动记录该模块。当第二次再导入该模块时,python会直接到字典中查找,从而加快程序运行的速度。它拥有字典所拥有的一切方法。
import sys
print(sys.version,type(sys.version))
print(sys.version_info)
version = sys.version_info
print(str(version.major) + '.' + str(version.minor))
print(sys.platform)
print('this is a error',sys.stderr)
print('this is a error',sys.stdin)
print('this is a error',sys.stdout)
/usr/local/python3/bin/python3.6 /root/PycharmProjects/day12/01_常用模块.py
3.6.4 (default, Jun 1 2018, 18:57:40)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] <class 'str'>
sys.version_info(major=3, minor=6, micro=4, releaselevel='final', serial=0)
3.6
linux
this is a error <_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>
this is a error <_io.TextIOWrapper name='' mode='r' encoding='UTF-8'>
this is a error <_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>
在Python中,与时间处理有关的模块就包括:time,datetime以及calendar
1.在Python中,通常有这几种方式来表示时间:1)时间戳 2)格式化的时间字符串 3)元组(struct_time)共九个元素。由于Python的time模块实现主要调用C库,所以各个平台可能有所不同。
2.UTC(Coordinated Universal Time,世界协调时)亦即格林威治天文时间,世界标准时间。在中国为UTC+8。DST(Daylight Saving Time)即夏令时。
3.时间戳(timestamp)的方式:通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。返回时间戳方式的函数主要有time(),clock()等。
4.元组(struct_time)方式:struct_time元组共有9个元素,返回struct_time的函数主要有gmtime(),localtime(),strptime()。下面列出这种方式元组中的几个元素:
元组(struct_time)方式中的几个元素:
time模块中常用的几个函数:
## 导入time模块
1)time.localtime([secs]):将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。
print(time.localtime())
time.struct_time(tm_year=2018, tm_mon=6, tm_mday=14, tm_hour=10, tm_min=42, tm_sec=29, tm_wday=3, tm_yday=165, tm_isdst=0)
2)time.gmtime([secs]):和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。
## 注意:这里的tm_wday=3表示的是周几,但是要在这个返回值的基础上往后推一天,即表示的是周四,而不是周三
print(time.gmtime())
time.struct_time(tm_year=2018, tm_mon=6, tm_mday=14, tm_hour=2, tm_min=44, tm_sec=41, tm_wday=3, tm_yday=165, tm_isdst=0)
3)time.time():返回当前时间的时间戳。
print(time.time())
1528944281.1089418
4)time.mktime(t):将一个struct_time转化为时间戳。
print(time.mktime(time.localtime()))
1528944559.0
5)time.sleep(secs):线程推迟指定的时间运行。单位为秒。
6)time.clock():这个需要注意,在不同的系统上含义不同。在UNIX系统上,它返回的是“进程时间”,它是用秒表示的浮点数(时间戳)。
而在WINDOWS中,第一次调用,返回的是进程运行的实际时间。而第二次之后的调用是自第一次调用以后到现在的运行时间。(实际上是以WIN32上QueryPerformanceCounter()为基础,它比毫秒表示更为精确)
if __name__ == '__main__':
time.sleep(1)
print("clock1:%s" %(time.clock()))
time.sleep(1)
print("clock1:%s" %(time.clock()))
time.sleep(1)
print("clock1:%s" %(time.clock()))
/usr/local/python3/bin/python3.6 /home/kiosk/PycharmProjects/day_08/01_time.py
clock1:3.35238137808e-006
clock2:1.00004944763
clock3:2.00012040636
## 其中第一个clock()输出的是程序运行时间
## 第二、三个clock()输出的都是与第一个clock的时间间隔
7)time.asctime([t]):把一个表示时间的元组或者struct_time表示为这种形式:'Sun Jun 20 23:21:05 1993'。如果没有参数,将会将time.localtime()作为参数传入。
print(time.asctime())
Thu Jun 14 11:05:47 2018
8)time.ctime([secs]):把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式。如果参数未给或者为None的时候,将会默认time.time()为参数。它的作用相当于time.asctime(time.localtime(secs))。
print(time.ctime())
print(time.ctime(time.time()))
Thu Jun 14 11:08:59 2018
Thu Jun 14 11:08:59 2018
9)time.strftime(format[, t]):把一个代表时间的元组或者struct_time(如由time.localtime()和time.gmtime()返回)转化为格式化的时间字符串。如果t未指定,将传入time.localtime()。如果元组中任何一个元素越界,ValueError的错误将会被抛出。
print(time.strftime("%Y-%m-%d %X",time.localtime()))
2018-06-14 11:11:23
10)time.strptime(string[, format]):把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作。
s = '2018-6-18'
print(time.strptime(s,'%Y-%m-%d'))
time.struct_time(tm_year=2018, tm_mon=6, tm_mday=18, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=0, tm_yday=169, tm_isdst=-1)
# 4. 获取指定文件创建时间;
atime = os.path.getatime('/etc/passwd')
# 把看不懂的时间戳转化为字符串格式;
print(time.ctime(atime))
# 把看不懂的时间戳转化为元组格式
print(time.localtime(atime))
# 将元组格式转化为时间戳格式
tuple_time = time.localtime()
print(time.mktime(tuple_time))
# 将元组格式转化为字符串显示
print(time.strftime('%D'))
print(time.strftime('%D', tuple_time))
print(time.strftime('%Y-%m-%d', tuple_time))
print(time.strftime('%F', tuple_time))
print(time.strftime('%T', tuple_time))
# 将字符串格式转化为元组
s = '2008-10-30'
print(time.strptime(s, '%Y-%m-%d'))
print(time.strptime("12:00:40", '%H:%M:%S'))
import os
from datetime import date,time,datetime,timedelta
# 1. date
# 显示当前的日期;
today = date.today()
print(today)
2018-06-15
# 转化为其他字符串格式
print(today.strftime('%m/%d/%Y'))
06/15/2018
# 转化为元组格式便于解析
print(today.timetuple())
time.struct_time(tm_year=2018, tm_mon=6, tm_mday=15, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=4, tm_yday=166, tm_isdst=-1)
# 替换年月日;
print(today.replace(day=30))
print(today.replace(year=2050))
print(today.replace(month=8))
2018-06-30
2050-06-15
2018-08-15
# 转化时间戳为date对象;
atime = os.path.getmtime('/etc/passwd')
d = date.fromtimestamp(atime)
print(d,type(d))
2018-04-15 'datetime.date'>
# 2.time
t = time(10,20,45)
print(t.strftime("%H:%M"))
print(t.replace(hour=11))
print(t.replace(minute=30))
print(t.replace(second=59))
10:20
11:20:45
10:30:45
10:20:59
# 3. datetime
today = date.today()
d1 = datetime.today()
print(d1)
2018-06-15 10:18:30.961094
# 4. delta (只对day)
d2 = datetime.today()
print(d2)
yesterday = d2 - timedelta(days=1) ## 时间向前推一天
print(yesterday.strftime('%Y-%m-%d'))
2018-06-15 10:21:20.704758
2018-06-14
shutil 是高级的文件,文件夹,压缩包处理模块。
1.应用
import shutil
# 将文件内容拷贝到另一个文件中
shutil.copyfileobj(fsrc, fdst[, length])
底层原理:
def copyfileobj(fsrc, fdst, length=16*1024):
"""copy data from file-like object fsrc to file-like object fdst"""
while 1:
# 每次读取指定个字节数, 直到读不到内容则跳出;
buf = fsrc.read(length)
if not buf:
break
fdst.write(buf)
shutil.copyfileobj(open('old.xml','r'),open('new.xml','w'))
# 拷贝文件
shutil.copyfile(src, dst)
shutil.copyfile('f1.log','f2.log')
# 仅拷贝权限。内容、组、用户均不变
shutil.copymode(src, dst)
shutil.copymode('f1.log', 'f2.log')
# 仅拷贝状态的信息,包括:mode bits, atime, mtime, flags
shutil.copystat(src, dst)
shutil.copystat('f1.log', 'f2.log')
# 拷贝文件和权限
shutil.copy(src, dst)
shutil.copy('f1.log', 'f2.log')
# 拷贝文件和状态信息
shutil.copy2(src, dst)
shutil.copy2('f1.log', 'f2.log')
# 递归的去拷贝文件夹
shutil.copytree('/var/log', '/mnt/log', ignore=shutil.ignore_patterns('*.log')) 拷贝文件时忽略以log结尾的文件
shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.log'))
# 递归的去删除文件
shutil.rmtree(path[, ignore_errors[, onerror]])
shutil.rmtree('f1')
# 递归的去移动文件,它类似mv命令,其实就是重命名。
shutil.move(src, dst)
shutil.move('folder1', 'folder3')
# 创建压缩包并返回文件路径,例如:zip、tar
shutil.make_archive(base_name, format,...)
base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
如:www =>保存至当前路径
如:/Users/wupeiqi/www =>保存至/Users/wupeiqi/
format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
root_dir: 要压缩的文件夹路径(默认当前目录)
owner: 用户,默认当前用户
group: 组,默认当前组
logger: 用于记录日志,通常是logging.Logger对象
shutil.make_archive('/etc/passwd', "gztar", '/mnt/')
套接字是为特定网络协议(例如TCP/IP,ICMP/IP,UDP/IP等)套件对上的网络应用程序提供者提供当前可移植标准的对象。它们允许程序接受并进行连接,如发送和接受数据。为了建立通信通道,网络通信的每个端点拥有一个套接字对象极为重要。和大多数语言一样,Python 支持面向连接和无连接,实现接口功能与步骤也大致相同。
1)面向连接即需要先连接然后通讯, 面向连接主要协议就是传输控制协议(tcp),要创建tcp套接字时需要指定套接字类型为 SOCK_STRAM,表达了他作为流套接字的特点。
2)无连接,顾名思义无需建立连接就可以进行通讯,这时数据到达顺序、可靠性就无法保证了。实现这种连接的协议就是用户数据包协议(udp)。创建UDP时需要指定套接字类型为 SOCK_DGRAM。
在使用的时候,每个socket都被绑定到一个特定的IP地址和端口。IP地址是一个由4个数组成的序列,这4个数均是范围 0~255中的值(例如,220,176,36,76);端口数值的取值范围是0~65535。端口数小于1024的都是为众所周知的网络服务所保留的(例如Web服务使用的80端口);最大的保留数被存储在socket模块的IPPORT_RESERVED变量中。你也可以为你的程序使用另外的端口数值。
地址127.0.0.1是本机地址;它始终指向当前的计算机。
TCP服务器端:
# 1. 第一步是创建socket对象。调用socket构造函数。如:
socket = socket.socket( family, type )
family参数代表地址家族,可为AF_INET或AF_UNIX。AF_INET家族包括Internet地址,AF_UNIX家族用于同一台机器上的进程间通信。type参数代表套接字类型,可为SOCK_STREAM(流套接字)和SOCK_DGRAM(数据报套接字)
# 2. 第二步是将socket绑定到指定地址。这是通过socket对象的bind方法来实现的:
socket.bind( address )
由AF_INET所创建的套接字,address地址必须是一个双元素元组,格式是(host,port)。host代表主机,port代表端口号。如果端口号正在使用、主机名不正确或端口已被保留,bind方法将引发socket.error异常。
# 3. 第三步是使用socket套接字的listen方法接收连接请求。
socket.listen( backlog )
backlog指定最多允许多少个客户连接到服务器。它的值至少为1。收到连接请求后,这些请求需要排队,如果队列满,就拒绝请求
# 4. 第四步是服务器套接字通过socket的accept方法等待客户请求一个连接。
connection, address = socket.accept()
调 用accept方法时,socket会时入“waiting”状态。客户请求连接时,方法建立连接并返回服务器。accept方法返回一个含有两个元素的 元组(connection,address)。第一个元素connection是新的socket对象,服务器必须通过它与客户通信;第二个元素 address是客户的Internet地址。
# 5. 第五步是处理阶段,服务器和客户端通过send和recv方法通信(传输 数据)。服务器调用send,并采用字符串形式向客户发送信息。send方法返回已发送的字符个数。服务器使用recv方法从客户接收信息。调用recv 时,服务器必须指定一个整数,它对应于可通过本次方法调用来接收的最大数据量。recv方法在接收数据时会进入“blocked”状态,最后返回一个字符 串,用它表示收到的数据。如果发送的数据量超过了recv所允许的,数据会被截短。多余的数据将缓冲于接收端。以后调用recv时,多余的数据会从缓冲区 删除(以及自上次调用recv以来,客户可能发送的其它任何数据)。
# 6. 传输结束,服务器调用socket的close方法关闭连接
import os
import socket
HOST = '172.25.254.1'
PORT = 6666
ConnectCount = 5
MaxByte = 1024*8
# 1. server端程序, 创建socket对象
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 绑定ip和端口
serverSocket.bind((HOST, PORT))
# 3. 监听是否有客户端连接;这里的ConnectCount代表最多只允许几个客户端连接;
serverSocket.listen(ConnectCount)
print("Server is starting.......")
# 4. 如果有客户端连接, 则接收客户端连接, 返回2个值, 一个是客户端的socket对象;
# 另外一个是客户端连接服务端的ip和端口
clientSocket, address = serverSocket.accept()
while True:
# 5. 接收客户端的消息;MaxByte代表每次最多接收的字节数;
cmd = clientSocket.recv(MaxByte).decode('utf-8')
print("接收到客户端的消息:", cmd)
# 判断命令是否执行成功?
if os.system(cmd) == 0:
# 6. 给客户端一个响应, 回复消息;
cmd_res = os.popen(cmd).read()
else:
cmd_res = "%s命令找不到" %(cmd)
# encode, 并且发送消息
cmd_res = cmd_res.encode('utf-8')
clientSocket.send(cmd_res)
# 7. 关闭socket对象
serverSocket.close()
/usr/local/python3/bin/python3.6 /root/PycharmProjects/day13/01_socket-server.py
Server is starting......
sh: $'\344\275\240\346\230\257\357\274\237': command not found
接收到客户端的消息: 你是?
接收到客户端的消息: ls
01_socket-server.py
02_socket-client.py
接收到客户端的消息: df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mapper/rhel-root 45021720 27952324 17069396 63% /
devtmpfs 1923876 0 1923876 0% /dev
tmpfs 1940748 148 1940600 1% /dev/shm
tmpfs 1940748 187216 1753532 10% /run
tmpfs 1940748 0 1940748 0% /sys/fs/cgroup
/dev/mapper/rhel-home 21980688 15786540 6194148 72% /home
/dev/sda7 508588 167912 340676 34% /boot
tmpfs 388152 28 388124 1% /run/user/1001
TCP客户端:
# 1. 第一步是创建一个socket以连接服务器:socket = socket.socket( family, type )
# 2. 第二步是使用socket的connect方法连接服务器。对于AF_INET家族,连接格式如下:socket.connect( (host,port) )host代表服务器主机名或IP,port代表服务器进程所绑定的端口号。如连接成功,客户就可通过套接字与服务器通信,如果连接失败,会引发socket.error异常。
# 3. 第三步是处理阶段,客户和服务器将通过send方法和recv方法通信。
# 4. 传输结束,客户通过调用socket的close方法关闭连接。
import socket
host = '172.25.254.1'
port = 6666
# 1. 创建socket;
clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 连接远程主机
clientSocket.connect((host, port))
mysock = clientSocket.getsockname()
print("连接{0}的socket为{1}".format(host, mysock))
while True:
cmd = input("client>>:").encode('utf-8')
# 3.给server主机发送消息;
clientSocket.send(cmd)
# 4. 接收服务端返回的消息;
reply = clientSocket.recv(1024*8).decode('utf-8')
print("接收到服务端的消息:", reply)
# 5. 关闭socket对象
clientSocket.close()
连接172.25.254.10的socket为('172.25.254.10', 33889)
client>>你是?
接收到服务端的消息 你是?命令找不到
client>>ls
接收到服务端的消息 01_socket-server.py
02_socket-client.py
client>>df
接收到服务端的消息 Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mapper/rhel-root 45021720 27952324 17069396 63% /
devtmpfs 1923876 0 1923876 0% /dev
tmpfs 1940748 148 1940600 1% /dev/shm
tmpfs 1940748 187216 1753532 10% /run
tmpfs 1940748 0 1940748 0% /sys/fs/cgroup
/dev/mapper/rhel-home 21980688 15786540 6194148 72% /home
/dev/sda7 508588 167912 340676 34% /boot
tmpfs 388152 28 388124 1% /run/user/1001
client>>
paramiko基于ssh用于连接远程服务器, 执行命令, 上传和下载;
1.基于用户名和密码远程连接, 执行命令;
# 1. 创建SSH对象;
ssh = paramiko.SSHClient()
# 2. 如果ip之前不在know_host里面, 自动解决yes/no的问题;
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 3. 连接服务器
ssh.connect(hostname='172.25.254.1', port=22, username='root', password='redhat')
#4. 远程执行命令 (stdin:标准输入 stdout:标准输出 stderr:标准错误)
stdin, stdout, stderr = ssh.exec_command('hostname')
# 5. 获取命令结果;
result = stdout.read()
print(result)
# 6. 关闭ssh连接
ssh.close()
/usr/local/python3/bin/python3.6 /root/PycharmProjects/day13/03_paramiko.py
b'foundation10.example.com\n'
2.基于用户名和密码远程连接, 上传和下载文件;(SFTPClient)
transport = paramiko.Transport(('172.25.254.1', 22))
transport.connect(username='root', password='redhat')
sftp = paramiko.SFTPClient.from_transport(transport)
# 将本机的文件上传到远程服务器上;
sftp.put('/etc/passwd', '/tmp/westos89')
# 下载远程主机的文件到local;
sftp.get('/tmp/westos89', '/tmp/qq')
sftp.close()
[root@localhost tmp]# ll /tmp/westos
-rw-r--r--. 1 root root 3342 6月 15 04:17 /tmp/westos
[root@localhost tmp]# logout
Connection to 172.25.254.1 closed.
[kiosk@foundation10 tmp]$ ll /tmp/qq
-rw-r--r-- 1 root root 3342 6月 15 16:17 /tmp/qq
3.基于paramiko的主机批量管理工具
需求:
1. 主机分组;对选中的主机进行批量操作;
2. 登陆后可显示主机分组, =根据分组查看主机列表;
3. 可批量执行命令, 发送文件并实时显示结果;
4. 没有基于无密码认证, 每台主机的用户名和主机名均不同;
主机操作设置
settings.py,其所在目录设置为根目录
host_info = {
'web': {
'web1': {'ip': '172.25.254.10', 'port': 22, 'username': 'root', 'password': 'redhat'},
'web2': {'ip': '172.25.254.1', 'port': 22, 'username': 'root', 'password': 'westos'},
'web3': {'ip': '172.25.254.2', 'port': 22, 'username': 'root', 'password': 'redhat'},
},
'mysql': {
'mysql1': {'ip': '172.25.254.10', 'port': 22, 'username': 'root', 'password': 'redhat'},
'mysql2': {'ip': '172.25.254.1', 'port': 22, 'username': 'root', 'password': 'westos'}
},
'zabbix': {
'zabbix1': {'ip': '172.25.254.1', 'port': 22, 'username': 'root', 'password': 'westos'}
}
}
导入settings模块(独立的settings.py文件可以作为模块导入)
import paramiko
from settings import host_info
class RomoteHost(object):
def __init__(self, host, port, username, password, cmd):
self.host = host
self.port = port
self.username = username
self.password = password
self.cmd = cmd
def run(self):
"""执行命令时的分离操作"""
# cmd hostname
cmd_str = self.cmd.split()[0] # 第0个索引代表命令
# 类的反射(hasattr):根据对象,获取对应的类拥有的属性和方法
if hasattr(self, 'do_'+cmd_str): # 判断方法'do_'+cmd_str是否存在
getattr(self, 'do_'+cmd_str)() # 获取方法,后面加括号可以将这个方法运行。
else:
print("目前不支持")
def do_cmd(self):
# 1. 创建SSH对象;
ssh = paramiko.SSHClient()
# 2. 如果之前不再know_host里面, 自动解决yes/no的问题;
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 3. 连接服务器
ssh.connect(hostname=self.host, port=self.port,
username=self.username, password=self.password)
# 4. 远程执行命令
# self.cmd = 'cmd hostname'
now_cmd = self.cmd.split()[1:]
now_cmd = " ".join(now_cmd) # 命令以空格隔开
print(now_cmd)
stdin, stdout, stderr = ssh.exec_command(now_cmd)
# 5. 获取命令结果;
result = stdout.read() # 输出结果
print("%s".center(50, '*') %(self.host))
print(result.decode('utf-8'))
# 6. 关闭ssh连接
ssh.close()
def do_put(self):
transport = paramiko.Transport((self.host, self.port))
transport.connect(username=self.username, password=self.password)
sftp = paramiko.SFTPClient.from_transport(transport)
# put /etc/passwd
now_cmd = self.cmd.split()[1:]
if len(now_cmd) == 2:
file1 = now_cmd[0] # 本机文件
file2 = now_cmd[1] # 上传到服务端的文件(file1 !=file2,即上传中file1改名为file)
print(file1, file2)
# 将本机的文件上传到远程服务器上;
sftp.put(file1, file2)
elif len(now_cmd) == 1:
file1 = now_cmd[0]
sftp.put(file1)
else:
print('options error')
print( print("%s".center(50, '*') %(self.host)))
# # 下载远程主机的文件到local;
# sftp.get('/tmp/westos89', '/tmp/qq')
sftp.close()
def do_get(self):
print('get.....')
def select_host_list():
"""列出指定主机组的主机成员信息"""
# 1. 列出所有的主机组名称
for index,key in enumerate(host_info):
print(index+1, key, len(host_info[key]))
# len(host_info[key] 主机数量
# 2. 用户选择操作的主机
while True:
group = input("选择主机组(eg:web)>>")
if group not in host_info:
print('该主机组%s不存在' %(group))
else:
# 显示该主机组所有成员的ip:
groups = host_info[group]
print("主机组显示".center(50, '*'))
for key, value in groups.items():
# item == 'web1',
print(key, value['ip'])
# groups是选中的主机组成员所有信息;
return groups
def main(choose_host):
while True:
# 接收用户对选中主机的操作
# cmd hostname
# put /etc/passwd
# get /etc/passwd
cmd = input(">>:").strip()
if cmd:
# 依次遍历选中的所有主机
for key in choose_host:
host = choose_host[key]['ip']
port = choose_host[key]['port']
username = choose_host[key]['username']
password = choose_host[key]['password']
obj = RomoteHost(host, port, username, password, cmd)
obj.run()
else:
continue
choose_host = select_host_list()
main(choose_host)
/usr/local/python3/bin/python3.6 /root/PycharmProjects/day13/04_基于paramiko的主机批量管理工具.py
1 web 3
2 mysql 2
3 zabbix 1
选择主机组(eg:web)>>web
**********************主机组显示***********************
web1 172.25.254.10
web2 172.25.254.1
web3 172.25.254.2
>>:cmd hostname
hostname
************************172.25.254.10************************
foundation10.example.com
hostname
************************172.25.254.1************************
localhost
hostname
************************172.25.254.2************************
localhost
>>:cmd las
las
************************172.25.254.10************************
bash: las: command not found
las
************************172.25.254.1************************
las
************************172.25.254.2************************
>>: cmd touch /mnt/hello
touch /mnt/hello
************************172.25.254.10************************
touch /mnt/hello
************************172.25.254.1************************
touch /mnt/hello
************************172.25.254.2************************
[root@localhost ~]# ll /mnt/hello
-rw-r--r--. 1 root root 0 6月 15 08:02 /mnt/hello
[root@localhost ~]# ll /mnt/hello
-rw-r--r--. 1 root root 0 6月 15 08:02 /mnt/hello
[kiosk@foundation10 mnt]$ ll hello
-rw-r--r-- 1 root root 0 6月 15 20:01 hello