文章目录
文件的读写
Python中实现文件的读写操作其实非常简单,通过Python内置的open
函数,我们可以指定文件名、操作模式、编码信息等来获得操作文件的对象,接下来就可以对文件进行读写操作了
操作模式 | 具体含义 |
---|---|
'r' | 读取 (默认) |
'w' | 写入(会先截断之前的内容) |
'x' | 写入,如果文件已经存在会产生异常 |
'a' | 追加,将内容写入到已有文件的末尾 |
'b' | 二进制模式 |
't' | 文本模式(默认) |
'+' | 更新(既可以读又可以写 |
读文件
读取文本文件时,需要在使用open
函数时指定好带路径的文件名(可以使用相对路径或绝对路径)并将文件模式设置为'r'
(如果不指定,默认值也是'r'
),然后通过encoding
参数指定编码(如果不指定,默认值是None,那么在读取文件时使用的是操作系统默认的编码),如果不能保证保存文件时使用的编码方式与encoding参数指定的编码方式是一致的,那么就可能因无法解码字符而导致读取失败。
def main():
f=open('再别康桥.txt','r',encoding='utf-8')
print(f.read())
f.close()
如果open
函数指定的文件并不存在或者无法打开,那么将引发异常状况导致程序崩溃。为了让代码有一定的健壮性和容错性,我们可以使用Python的异常机制对可能在运行时发生状况的代码进行适当的处理。
def main():
try:
f = open('再别康桥.txt', 'r', encoding='utf-8')
print(f.read())
except FileNotFoundError:
print('无法打开指定文件!')
except LookupError:
print('指定了未知的编码!')
except UnicodeDecodeError:
print('读取文件时解码错误?!')
finally:
f.close()
if __name__ == '__main__':
main()
在Python中,我们可以将那些在运行时可能会出现状况的代码放在try
代码块中,在try
代码块的后面可以跟上一个或多个except
来捕获可能出现的异常状况。由于finally
块的代码不论程序正常还是异常都会执行到因此我们通常把finally
块称为“总是执行代码块”,它最适合用来做释放外部资源的操作。如果不愿意在finally
代码块中关闭文件对象释放资源,也可以使用上下文语法,通过with
关键字指定文件对象的上下文环境并在离开上下文环境时自动释放文件资源
def main():
try:
with open('再别康桥.txt','r',encoding='utf-8') as f:
print(f.read())
if __name__=='__main__':
main()
除了使用文件对象的read
方法读取文件之外,还可以使用for-in
循环逐行读取或者用readlines
方法将文件按行读取到一个列表容器中。
import time
def main():
# 一次性读取整个文件内容
with open('致橡树.txt', 'r', encoding='utf-8') as f:
print(f.read())
# 通过for-in循环逐行读取
with open('致橡树.txt', mode='r') as f:
for line in f:
print(line, end='')
time.sleep(0.5)
print()
# 读取文件按行读取到列表中
with open('致橡树.txt') as f:
lines = f.readlines()
print(lines)
if __name__ == '__main__':
main()
写文件
在使用open
函数时指定好文件名并将文件模式设置为'w'
即可。注意如果需要对文件内容进行追加式写入,应该将模式设置为'a'
。如果要写入的文件不存在会自动创建文件而不是引发异常。
from math import sqrt
def is_prime(n):
assert n > 0
for factor in range(2, int(sqrt(n)) + 1):
if n % factor == 0:
return False
return True if n == 1 else False
def main():
filenames = ['a.txt', 'b.txt', 'c.txt']
fs_list = []
try:
#把可能出状况(在执行有风险)的代码放到try代码保护执行
for filename in filenames:
fs_list.append(open(filename, 'w', encoding='utf-8'))
for number in range(10000):
if is_prime(number):
if number < 100:
fs_list[0].write(str(number) + '\n')
elif number < 1000:
fs_list[1].write(str(number) + '\n')
else:
fs_list[2].write(str(number) + '\n')
except FileNotFoundError:
#except可以写多个分别用于处理不同的异常情况 else finally只有一个
print('打开文件时出错')
except IOError:
#如果try中出现了状况就通过except来铺货错误(异常)进行对应的处理
print('读写文件时出错')
else:
pass
#如果没有出状况那么可以把无风险的代码放到else中执行
finally:
print('释放文件资源')
#此处是最好的释放外部资源的位置因为不管程序正常还是异常 这里的代码一定会执行
for fs in fs_list:
fs.close()
print('程序执行结束')
if __name__ == '__main__':
main()
写二进制文件
def main():
try:
with open('123.jpg','rb') as fs1:
date=fs1.read()
with open('456.jpg','wb') as fs2:
fs2.write(date)
except FileNotFoundError as e:
print(e)
print('指定文件无法打开')
except IOError:
print('读写文件时出错')
print('程序执行结束')
if __name__ == '__main__':
main()
读写JSON
文件
json
模块主要有四个比较重要的函数,分别是:- dump - 将Python对象按照JSON格式序列化到文件中
- dumps - 将Python对象处理成JSON格式的字符串
- load - 将文件中的JSON数据反序列化成对象
- loads - 将字符串的内容反序列化成Python对象
def main():
try:
with open('data.json','r',encoding='utf-8') as fs:
yourdict=json.load(fs)
print(yourdict)#youdict是一个字典或列表
正则表达式
在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。
Python提供re模块支持正则表达式的应用
函数 | 说明 |
---|---|
compile(pattern, flags=0) | 编译正则表达式返回正则表达式对象 |
match(pattern, string, flags=0) | 用正则表达式匹配字符串 成功返回匹配对象 否则返回None |
search(pattern, string, flags=0) | 搜索字符串中第一次出现正则表达式的模式 成功返回匹配对象 否则返回None |
split(pattern, string, maxsplit=0, flags=0) | 用正则表达式指定的模式分隔符拆分字符串 返回列表 |
sub(pattern, repl, string, count=0, flags=0) | 用指定的字符串替换原字符串中与正则表达式匹配的模式 可以用count指定替换的次数 |
fullmatch(pattern, string, flags=0) | match函数的完全匹配(从字符串开头到结尾)版本 |
findall(pattern, string, flags=0) | 查找字符串所有与正则表达式匹配的模式 返回字符串的列表 |
finditer(pattern, string, flags=0) | 查找字符串所有与正则表达式匹配的模式 返回一个迭代器 |
purge() | 清除隐式编译的正则表达式的缓存 |
re.I / re.IGNORECASE | 忽略大小写匹配标记 |
re.M / re.MULTILINE | 多行匹配标记 |
常用的元字符
代码 | 说明 |
---|---|
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母或数字或下划线或汉字 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
\b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
import re
def verifier(username):
"""
判断用户名是否有效
:param username: 用户名(数字字母下划线构成 长度为6-20)
:return: 用户名有效返回真 无效返回假
"""
if 6<len(username)<20:
for index in range(len(username)):
if not '0'<=username[index]<='9' or 'A'<=username[index]<='Z' or \
'a' <= username[index] <= 'z' or username[index]=='_':
return False
return True
return False
def main():
print(verifier('1254'))
print(verifier('adsds15_'))
print(verifier('ghjjfff5545__-'))
以前的我们都会像上面这样写,但有了正则表达式,就简单了很多如下所示
username='dghfgdj_'
if re.match(r'^\w{6,20}$',username):#从头开始匹配
#re.search(r'^\w{6,20}$', username)#从任意位置开始匹配
print('匹配成功!')
else:
print('匹配失败!')
如果想要打印出匹配的内容可以这样写:
m=re.match(r'^\w{6,20}$',username
print(m)
if m:
print(m.span())#匹配的范围
print(m.group())#匹配的内容
if __name__ == '__main__':
main()
字符转义
如果你想查找元字符本身的话,比如你查找.,或者*,就出现了问题:你没办法指定它们,因为它们会被解释成别的意思。这时你就得使用\来取消这些字符的特殊意义。因此,你应该使用.和*。当然,要查找\\本身,你也得用\.
重复
代码/语法 | 说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
def main():
sentence='aabacbdaab'
m=re.match(r'a.*?b',sentence)#a重复零次一次或多次
print(m)
if __name__=='__main__':
main()
结果:
<_sre.SRE_Match object; span=(0, 3), match='aab'>
字符类
要想查找数字,字母或数字,空白是很简单的,因为已经有了对应这些字符集合的元字符
#拆分字符
def main():
sentence='You go your way, I will go mine!'
mylist=re.split(r'[\s,!]',sentence)
print(mylist)
if__name__=='__main__':
main()
结果:
['You', 'go', 'your', 'way', '', 'I', 'will', 'go', 'mine', '']
分支条件
正则表达式里的分枝条件指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用|把不同的规则分隔开。
#替换不想看到的字符
import re
def main():
sentence='我草你大爷的日你二舅'
pure=re.sub('[草操艹肏日干]|fuck|shit]|fuck|shit','*',
sentence,flags=re.IGNORECASE)
print(pure)
结果:
我*你大爷的*你二舅
分组
用小括号来指定子表达式(也叫做分组),然后就可以指定这个子表达式的重复次数了,也可以对子表达式进行其它一些操作。
#找出字符串中数字字串,并求平均
import re
from re import findall,sub
def foo(m):
val=m.group('fool')
print(val)
def main():
sentence='656ghshgf556hsf55hsdh'
pattern=re.findall(r'\d+',sentence)
print(pattern)
my_list=list(map(int,pattern))
print(sum(my_list) / len(my_list))
#建了两个分组并分别命名,这样有利于函数用哪个分组,对其进行操作
print(sub(r'(?P<fool>\d+)(?P<du>[hg])',foo,sentence))
#第一个分组取用数字字串,第二个分组判断数字后是不是以h或g结尾,如果是,就用‘’替代
if __name__ == '__main__':
main()
结果:
['656', '556', '55']
422.3333333333333
656
556
55
hshgfsfsdh
反义
有时需要查找不属于某个能简单定义的字符类的字符。比如想查找除了数字以外,其它任意字符都行的情况,这时需要用到反义:
代码/语法 | 说明 |
---|---|
\W | 匹配任意不是字母,数字,下划线,汉字的字符 |
\S | 匹配任意不是空白符的字符 |
\D | 匹配任意非数字的字符 |
\B | 匹配不是单词开头或结束的位置 |
[^X] | 匹配除了x以外的任意字符 |
[^aeiou ] | 匹配除了aeiou这几个字母以外的任意字符 |
反向引用
分类 | 代码/语法 | 说明 |
---|---|---|
捕获 | (exp) | 匹配exp,并捕获文本到自动命名的组里 |
(?< name >exp) | 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name’exp) | |
(?:exp) | 匹配exp,不捕获匹配的文本,也不给此分组分配组号 | |
零宽断言 | (?=exp) | 匹配exp前面的位置 |
(?<=exp) | 匹配exp后面的位置 | |
(?!exp) | 匹配后面跟的不是exp的位置 | |
(?< !exp) | 匹配前面不是exp的位置 | |
注释 | (?#comment) | 这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读 |
import re
def main():
# 创建正则表达式对象 使用了前瞻和回顾来保证手机号前后不应该出现数字
pattern = re.compile(r'(?<=\D)1[34578]\d{9}(?=\D)')
sentence = '''
我的手机号是14588997755不是13245674578
'''
# 查找所有匹配并保存到一个列表中
mylist = re.findall(pattern, sentence)
print(mylist)
# 通过迭代器取出匹配对象并获得匹配的内容
for temp in pattern.finditer(sentence):
print(temp.group())
# 通过search函数指定搜索位置找出所有匹配
m = pattern.search(sentence)
while m:
print(m.group())
m = pattern.search(sentence, m.end())
if __name__ == '__main__':
main()
结果:
['14588997755']
<_sre.SRE_Match object; span=(6, 17), match='14588997755'>
14588997755
(6, 17)
14588997755
多重继承
除了从一个父类继承外,Python允许从多个父类继承。
class Father(object):
def __init__(self, name):
self._name = name
def drink(self):
print(self._name + '正在喝酒')
def gamble(self):
print(self._name + '正在喝饮料')
class Monk(object):
def __init__(self, nickname):
self._nickname = nickname
def eat_vegetable(self):
print(self._nickname + '正在吃斋')
def chant(self):
print(self._nickname + '正在念经')
class Musician(object):
def __init__(self, art_name):
self._art_name = art_name
def paino(self):
print(self._art_name + '正在弹钢琴')
def drink(self):
print(self._art_name + '正在喝润喉茶')
class Son( Father, Monk,Musician):
def __init__(self, name, nickname, art_name):
Father.__init__(self,name)
Monk.__init__(self,nickname)
Musician.__init__(self,art_name)
#儿子类继承父类,音乐家类,和尚类的属性,在传参的 位置非常重要在Musician类中也含有drink方法,但是先传递了Father方法 所以在主函数中输出的是 Father类的drink的方法
def main():
son = Son('王大锤', '玄清', '贝多芬')
son.drink()
son.gamble()
son.eat_vegetable()
Musician.drink(son)
if __name__ == '__main__':
main()
结果:
王大锤正在喝酒
王大锤正在喝饮料
玄清正在吃斋
贝多芬正在喝润喉茶
在多重继承中,子类可重写父类中的方法
from abc import ABCMeta, abstractmethod
class Father(object):
def __init__(self, name):
self._name = name
def drink(self):
print(self._name + '正在喝酒')
def gamble(self):
print(self._name + '正在打牌')
class Monk(object, metaclass=ABCMeta):
@abstractmethod
def eat_vegetable(self):
pass
def chant(self):
pass
class Musician(object, metaclass=ABCMeta):
@abstractmethod
def paino(self):
pass
def drink(self):
pass
#子类重写父类的方法
class Son(Father, Monk, Musician):
def __init__(self, name, nickname, art_name):
Father.__init__(self, name)
self._nickname = nickname
self._art_name = art_name
def eat_vegetable(self):
print(self._nickname + '正在吃斋')
def chant(self):
print(self._nickname + '正在念经')
def paino(self):
print(self._art_name + '正在弹琴')
def drink(self):
print(self._art_name + '正在喝白开水')
def main():
son = Son('王大锤', '玄清', '贝多芬')
son.drink()
son.gamble()
son.eat_vegetable()
if __name__ == '__main__':
main()
结果:
贝多芬正在喝白开水
王大锤正在打牌
玄清正在吃斋
多线程
如果一个任务执行的时间很长 可以把它分为多个任务 启用多线程 缩短执行时间
改善用户体验 让用户有更好的体验。一个进程可以划分为多个线程 线城是进程的执行单元, 也是操作系统分配CPU的基本单元。
创建线程的方式
-
直接创建Thread对象并通过T爱人和他参数指定线程启动后要执行的任务
-
继承Thraed自定义线程 通过重写run方法指定线程启动后执行的任务
from threading import Thread
class PrintThread(Thread):
def __init__(self, string, count):
super().__init__()
self._string = string
self._count = count
def run(self):
for _ in range(self._count):
print(self._string, end='', flush=True)
def main():
PrintThread('Ping', 10000).start()
PrintThread('Pomg', 20000).start()
if __name__ == '__main__':
main()
-
多线程类似于同时执行多个不同程序,多线程运行有如下优点:
- 使用线程可以把占据长时间的程序中的任务放到后台去处理。
- 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
- 程序的运行速度可能加快
- 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。
指令指针和堆栈指针寄存器是线程上下文中两个最重要的寄存器,线程总是在进程得到上下文中运行的,这些地址都用于标志拥有线程的进程地址空间中的内存。
- 线程可以被抢占(中断)。
- 在其他线程正在运行时,线程可以暂时搁置(也称为睡眠) – 这就是线程的退让。
守护线程
守护线程-不值得保留的线程-其它线程都执行完毕 守护线程结束。
daemon=Ture-将线程设置为守护线程。
```用矩形代替小车,定义一个类,用线程将五两小车以不同的速度,从一端移动到另外另外一端```
import pygame
from random import randint
from threading import Thread
from time import sleep
class Color(object):
#定义全局常量 颜色
Black = (0, 0, 0)
White = (225, 225, 225)
Gray = (242, 242, 242)
#静态方法 随机颜色
@staticmethod
def random_color():
r = randint(0, 225)
g = randint(0, 255)
b = randint(0, 255)
return (r,g,b)
class Car(object):
#定义小车的构造器,传入小车的坐标以及颜色
def __init__(self, x, y, color):
self._x = x
self._y = y
self._color = color
#小车以不同的速度移动起来
def move(self):
if self._x +80<950:
self._x += randint(1, 10)
#画小车
def draw(self, screen):
pygame.draw.rect(screen, self._color,
(self._x, self._y, 80, 40), 0)
def main():
class BackgroundTask(Thread):
def run(self):
#画屏幕以及边界
while True:
screen.fill(Color.Gray)
pygame.draw.line(screen, Color.Black, (130, 0), (130, 600), 4)
pygame.draw.line(screen, Color.Black, (950, 0), (950, 600), 4)
for car in cars:
car.draw(screen)
pygame.display.flip()
sleep(0.05)
for car in cars:
car.move()
cars = []
#小车列表 放入五个小车,并定义小车的起点位置与颜色
for index in range(5):
temp = Car(50, 50+index * 120, Color.random_color())
cars.append(temp)
pygame.init()
screen = pygame.display.set_mode([1000, 600])
#启用守护线程 当主函数运行结束时线程也结束
BackgroundTask(daemon=True).start()
running = True
while running:
#判断游戏界面是否QUIT
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.quit()
if __name__ == '__main__':
main()
线程保护
当多个线程访问一个资源 就有可能因为竞争资源导致资源错误,被多个线程访问的资源我们通常称为临界资源 访问临界资源时需要保护。
import time
from threading import Thread,Lock
class Account(object):
def __init__(self):
self._balance = 0
self._lock=Lock()
#?定义存钱行为并进行保护
def deposit(self, money):
if money > 0:
#当余额大于0时,启用保护
self._lock.acquire()
try:
new_balance = self._balance + money
#存钱需要一定的时间,避免多线程运行会出错,我们可用time来进行定义
time.sleep(0.01)
self._balance = new_balance
finally:
#释放保户
self._lock.release()
@property
def balance(self):
return self._balance
class AddMoneyTheady(Thread):
#构造账户线程
def __init__(self, account):
super().__init__()
self._account = account
#调用存钱方法,并定义每次存一块钱
def run(self):
self._account.deposit(1)
def main():
account = Account()
#定义一个线程列表
tlist = []
for _ in range(100):
#存100次,并构造线程对象
t = AddMoneyTheady(account)
#将线程加入到线程列表中
tlist.append(t)
#启动线程
t.start()
for t in tlist:
#当当前线程结束执行
t.join()
#打印余额
print('账户余额:%d' % account.balance)
if __name__ == '__main__':
main()
多进程
进程 操作系统分配内存基本单位 进程之间的内存是相互隔离的, 如果要进行通信通过Ipc管道。由于Python是跨平台的,自然也提供一个跨平台的多进程支持。multiprocessing
模块就是跨平台版本的多进程模式。multiprocessing
模块提供了一个Process
来代表一个进程对象。如果多个任务之间没有任何的联系(独立的子任务)而且希望利用CPU的多核特性,推荐使用多进程。
import subprocess
#def main():
#subprocess.call('calc')启用计算器
#subprocess.call('notepad')启用记事本
from multiprocessing import Process
import time,os
def output():
print(os.getpid())
while True:
print('Pong',end='',flush=True)
time.sleep(0.001)
def main():
Process(target=output).start()
while True:
print('Ping',end='',flush=True)
time.sleep(0.001)
if __name__ == '__main__':
main()
def main():
Process(target=output).start()
while True:
print('Ping',end='',flush=True)
time.sleep(0.001)
if __name__ == '__main__':
main()
用进程和线程分别启用下载任务
from threading import Thread
import random
def download(filename):
print('开始下载%s...' % filename)
#文件下载的时间
delay = random.randint(5, 15)
time.sleep(delay)
print('%s下载完成,用时%d秒' % (filename, delay))
#线程
class Download(Thread):
def __init__(self,filename):
super().__init__()
self._filename=filename
#钩子函数hook/回调函数callback
def run(self):
#下载文件
download(self._filename)
def main():
start = time.time()
t1 = Download('python.pdf')
t1.start()
t2 =Download('追光者.MP4')
t2.start()
#join()等待线程结束执行
t1.join()
t2.join()
end = time.time()
#计算下载任无从开始到结束的时间
print('总共耗时%f秒' % (end - start))
#进程
def main():
start = time.time()
#直接调用进程并调用download直接开始下载任务
p1 = Process(target=download, args=('python.pdf',))
p1.start()
p2 = Process(target=download, args=('追光者.MP4',))
p2.start()
p1.join()
p2.join()
end = time.time()
print('总共耗时%f秒' % (end - start))
if __name__ == '__main__':
main()
网络编程
我们可以利用网络编程在客户端与服务器之间进行传递消息。Socket模块可进行网络编程
语法:
socket.socket([family[, type[, proto]]])
参数:
family: 套接字家族可以使AF_UNIX或者AF_INET
type: 套接字类型可以根据是面向连接的还是非连接分为SOCK_STREAM或SOCK_DGRAM
protocol: 一般不填默认为0.
函数 | 描述 |
---|---|
服务器端套接字 | |
s.bind() | 绑定地址(host,port)到套接字, 在AF_INET下,以元组(host,port)的形式表示地址。 |
s.listen() | 开始TCP监听。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了。 |
s.accept() | 被动接受TCP客户端连接,(阻塞式)等待连接的到来 |
客户端套接字 | |
s.connect() | 主动初始化TCP服务器连接,。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。 |
s.connect_ex() | connect()函数的扩展版本,出错时返回出错码,而不是抛出异常 |
公共用途的套接字函数 | |
s.recv() | 接收TCP数据,数据以字符串形式返回,bufsize指定要接收的最大数据量。flag提供有关消息的其他信息,通常可以忽略。 |
s.send() | 发送TCP数据,将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。 |
s.sendall() | 完整发送TCP数据,完整发送TCP数据。将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。 |
s.recvfrom() | 接收UDP数据,与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。 |
s.sendto() | 发送UDP数据,将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。 |
s.close() | 关闭套接字 |
s.getpeername() | 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。 |
s.getsockname() | 返回套接字自己的地址。通常是一个元组(ipaddr,port) |
s.setsockopt(level,optname,value) | 设置给定套接字选项的值。 |
s.getsockopt(level,optname[.buflen]) | 返回套接字选项的值。 |
s.settimeout(timeout) | 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect()) |
s.gettimeout() | 返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None。 |
s.fileno() | 返回套接字的文件描述符。 |
s.setblocking(flag) | 如果flag为0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)。非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常。 |
s.makefile() | 创建一个与该套接字相关连的文件 |
构建服务器与客户端 之间可以传送消息(一收一发)
#服务器
from socket import socket, AF_INET, SOCK_STREAM
import time
import datetime
def main():
#创建一个基于tcp的服务器的套接字对象
#我们做的是应用级的产品或服务所以可以利用现有的传输服务来实现数据传输
server = socket()
#绑定Ip地址(网络上的主机的身份标识)和端口(用来区分不同服务的IP地址的拓展)
server.bind(('10.7.189.81', 6789)) # 本机
#开始监听客户端的连接
server.listen(512) #512为队列大小 是2的次幂
print('服务器已经启动正在监听...')
while True:
#通过accept方法 接收客户端的连接
#accept方法是一个阻塞式的方法 如果没有客户端连上来
#那么accept方法就会让代码阻塞 直到有客户端连接上
#accept 方法返回一个元祖 元祖中的第一个值是代表客户端的对象
#元祖中的第二个值又是一个元祖 其中有客户端的Ip地址和端口
client,addr = server.accept()
print(addr,'连接成功')
client.send(str(datetime.datetime.now()).encode('utf-8'))#time.localtime(time.time())
client.close()
#客户端
from socket import socket
def main():
client=socket()
#连接服务器
client.connect(('10.7.189.81',6789))
#接收服务器的消息
data=client.recv(512)
print(type(data))
#对接收的消息进行编码
print(data.decode('utf-8'))
if __name__ == '__main__':
main()
客户端与服务器之间收发消息,客户端发,服务器收,一致保持此状态(一收一发)
# 客户端
class MyTheade(Thread):
#构造线程
def __init__(self, news):
super().__init__()
self.news = news
def main():
client = socket()
#联接服务器
client.connect(('10.7.189.81', 6789))
#一直保持收接消息的状态
while True:
#输入传入的消息
news = input('??入:')
#启用线程
MyTheade(news).start()
#发送消息 并进行编码
client.send(str(news).encode('utf-8'))
#接收服务器端的消息 并编码
data = client.recv(512)
print(data.decode('utf-8'))
#服务器端
from socket import socket
from threading import Thread
class MyTheade(Thread):
def __init__(self,new):
super().__init__()
self.new=new
def main():
server = socket()
#绑定服务器与端口
server.bind(('10.7.189.81 ', 6789))
#监听客户端
server.listen(512)
print('服务器已经启动正在监听...')
#接收并显示客户端的ip,与连接状况
client, addr = server.accept()
print(addr, '连接成功')
while True:
#接收客户端发送的消息并进行编码并输出
data = client.recv(512)
print(data.decode('utf-8'))
#回复客户端回消息,并进行编码
new=input('你要发送的消息?:')
#启动线程
MyTheade(new).start()
client.send(new.encode('utf-8'))
if __name__ == '__main__':
main()
建立聊天室 并显示所有的聊天信息
# 服务器
from socket import socket
from threading import Thread
def main():
class ClientHandler(Thread):
#构造线程?,传入客户
def __init__(self, client):
super().__init__()
self._client = client
def run(self):
while True:
#有风险的语句 放在try里
try:
#接收客户端消息
data = self._client.recv(1024)
#如果收到byebye 将这个客户移除,并关闭她的端口
if data.decode('utf-8') == 'byebye':
clients.remove(self._client)
self._client.close()
break
#将每个客户发送消息到服务器
for client in clients:
client.send(data)
#将异常的客户移除
except Exception as e:
print(e)
clients.remove(self._client)
break
server = socket()
# 命令行参数 sys.argv
#绑定服吴器与端口
server.bind(('10.7.189.81', 12345))
#监听客户端
server.listen(512)
#定义客户列表
clients = []
while True:
#接收当前客户
curr_client, addr = server.accept()
#将客户放入客户列表中
clients.append(curr_client)
#启用线程,开始处理目前客户
ClientHandler(curr_client).start()
#客户端
from socket import socket
from threading import Thread
def main():
class RefreshScreenThread(Thread):
#构造刷新界面线程
def __init__(self, client):
super().__init__()
self._client = client
def run(self):
while running:
#接收所有客户消息并进行编码
data = self._client.recv(512)
print(data.decode('utf-8'))
#客户昵称
nickname = input('请输入你的昵称:')
#定义套接字
myclient = socket()
#连接服务器与端口
myclient.connect(('10.7.189.81', 12345))
running = True
#启用刷新界面消息功能
RefreshScreenThread(myclient).start()
while running:
#定义你要说的信息
content = input('请发言:')
#如果输入的是byebye,进行编码,发送到服务器,服务器会关闭当前的端口,客户端将终止循环
if content=='byebye':
myclient.send(content.encode('utf-8'))
running=False
else:
#将你的逆臣与消息进行编码发送到服务器
msg = nickname+':' + content
myclient.send(msg.encode('utf-8'))
if __name__ == '__main__':
main()
图片编程
我们可以利用文件的读写来给服务器或者客户端进行发送图片
#客户端
from socket import socket, SOCK_STREAM
from time import sleep
def main():
sender = socket(type=SOCK_STREAM)
#打开文件
with open('1.jpg', 'rb') as f:
#读取文件
data = f.read()
#计算文件的长度
datalen = len(data)
total = 0
while total < datalen:
#将文件切片发送到服务器
sender.sendto(data[total:total + 1024], address=('10.7.189.81', 6888))
total += 1024
sleep(0.001)
if __name__ == '__main__':
main()
#服务器
from socket import socket, SOCK_DGRAM
def main():
receiver = socket(type=SOCK_DGRAM)
#绑定服务器与端口
receiver.bind(('10.7.189.81', 6888))
data = bytes()
while True:
#接收客户端发送的切片信息
seg, addr = receiver.recvfrom(1024)
data += seg
#判断照片的大小
if len(data) >=137827:
break
#打开文件并写入文件
with open('2.jpg', 'wb') as f:
f.write(data)
print('图片已接收.')
邮件发送
我们也可以利用网络编程来发送邮件,Python中有MIMEText
函数,可利用这个函数进行发送邮件
发送普通邮件
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from smtplib import SMTP_SSL
#发送内容
content = """
我跟你说着玩的
今晚出去玩,明天开会
早点睡
"""
# MIME-Multipurpose Internet Maill
#输入的内容为普通格式 编码utf-8
message = MIMEText(content, 'plain', 'utf-8')
#发送邮件的主题
message['Subject'] = '今天请你吃饭'
#第一邮箱发信人邮箱,第二个为收件人邮箱
sender.sendmail('1435246152@qq.com', '1013622764@qq.com', message.as_string())
print('发送成功!')
发送附件
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from smtplib import SMTP_SSL
def main():
# 附件
sender = SMTP_SSL('smtp.qq.com', 465)
sender.login('1435246152@qq.com', 'trbytuakgrjlhdge')
message = MIMEMultipart()
message['Subject'] = '请查收文件的数据'
text_msg = MIMEText('附件中有关本月关键数据晴查收', 'plain', 'utf-8')
message.attach(text_msg)
att2 = MIMEText(open('1.xlsx', 'rb').read(), 'base64', 'utf-8')
att2['Content-Type'] = 'application/vnd.ms-excel'
att2['Content-Type'] = 'attachment;filename==foo.xlsx'
message.attach(text_msg)
sender.sendmail('1435246152@qq.com', '1013622764@qq.com', message.as_string())
print('发送成功!')