提示:记录一些vim编辑环境下常用命令以及pyhon3高级编程
目录
一.python3网络编程
1.udp
1.udp实现从linux发送数据到windows
2.接收数据到ubuntu
3.使用同一个套接字完成收发信息
4.一个udp聊天器案例
2.tcp实现
1.tcp-client发送信息青春版
2.tcp-server青春版
3.循环为多个客户端服务的服务器青春版
4.升级版的循环服务的服务器
5.案例-文件下载器
二.多任务
1.多任务(线程实现)
1.多任务-线程
2.继承Thread类完成多任务
3.函数里修改全局变量
4.互斥锁解决资源竞争问题
5.多任务实现udp聊天器
1.多任务(进程实现)
1.使用进程完成多任务
2.利用队列完成多任务进程之间的通信
3.案例-复制文件jia里所有文件青春版
4.案例-带进度条的文件夹拷贝器
3.多任务(协程实现)
1.迭代器-自己定义的类进行迭代青春版
2.迭代器-自己的类进行迭代
3.迭代器实现多任务(Fibonacci为例子)
4.生成器-实现斐波那契数列
5.生成器的一些知识
6.生成器send()实现多任务
7.通过yield完成多任务
8.greenlet多任务
9.gevent完成多任务
10.gevent多任务-2
11.案例-图片下载器
三.web服务器v3.1
1.正则表达式简介
1.正则判断变量名是否合理
2.正则判断常用邮箱地址
2.http
1.实现简单的http服务器
2.根据客户端需要完成http服务器
3.返回index页面http
4.使用多进程完成http服务器
5.使用多线程完成http
6.协程完成http服务器
7.单进程单线程非堵塞并发完成http服务器
8.单进程单线程非堵塞长连接
9.epoll实现http服务器
一.python3网络编程
1.udp
1.udp实现从linux发送数据到windows
windows编码是("gbk")
linux('utf-8')
import socket
def main():
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
while True:
sent_data = input("请输入您需要发送的信息")
if sent_data == 'exit':break
udp_socket.sendto(sent_data.encode('utf-8'),("172.21.126.225",8080))
udp_socket.close()
if __name__ =='__main__':
main()
解码用decode
编码用encode
发信息基本步骤:1.创建套接字
2.输入需要发送的信息
3.发送信息
4.关闭套接字
2.接收数据到ubuntu
收信息基本步骤:1.创建套接字
2.绑定端口号
3.调用函数recvfrom() 第一个返回值是信息,第二个是对方的地址
4.关闭套接字
import socket
def main():
# 创建套接字
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 绑定端口号
local_addr = ("",4657)
udp_socket.bind(local_addr)
recv_data = udp_socket.recvfrom(1024)
recv_msg = recv_data[0] # 接受的信息
recv_addr = recv_data[1] # 发送者的地址信息
print(f"{recv_addr}:{recv_msg}")
# udp_socket.sendto(b"haha",("172.21.126.225",8080))
udp_socket.close()
if __name__ =='__main__':
main()
3.使用同一个套接字完成收发信息
import socket
def main():
# 创建套接字
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 获取对方的ip/port
dest_ip = input("请输入对方的ip:")
dest_port = int(input("请输入对方的port:"))
# 从键盘获取数据
send_data = input("请输入要发送的数据:")
# 可以使用套接字收发数据
udp_socket.sendto(send_data.encode("utf-8"),(dest_ip,dest_port))
# 绑定端口号
# local_addr = ("",4657)
# udp_socket.bind(local_addr)
# 接手数据
recv_data = udp_socket.recvfrom(1024)
recv_msg = recv_data[0] # 接受的信息
recv_addr = recv_data[1] # 发送者的地址信息
print(f"{recv_addr}:{recv_msg}")
# udp_socket.sendto(b"haha",("192.168.220.1",8080))
udp_socket.close()
if __name__ =='__main__':
main()
4.一个udp聊天器案例
import socket
def send_msg(udp_socket):
"""发送消息"""
dest_ip = input("请输入对方的ip:")
dest_port = int(input("请输入对方的port:"))
send_data = input("请输入要发送的数据:")
# 可以使用套接字收发数据
udp_socket.sendto(send_data.encode("utf-8"),(dest_ip,dest_port))
def recv_msg(udp_socket):
"""接收数据"""
recv_data = udp_socket.recvfrom(1024)
recv_msg = recv_data[0].decode("gbk") # 接受的信息
recv_addr = recv_data[1] # 发送者的地址信息
print(f"{recv_addr}:{recv_msg}")
def main():
# 创建套接字
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#绑定信息
udp_socket.bind(("",7788))
# 获取对方的ip/port
# dest_ip = input("请输入对方的ip:")
# dest_port = int(input("请输入对方的port:"))
# 从键盘获取数据
while True:
print("-----dup聊天器-----")
print("1:发送消息")
print("2:接收消息")
print("0:退出聊天器")
op = input("请输入功能:")
if op == "1":
#发送消息
send_msg(udp_socket)
elif op == "2":
# 接收数据并显示
recv_msg(udp_socket)
elif op == '0':break
else:
print("输入有误")
# 绑定端口号
# local_addr = ("",4657)
# udp_socket.bind(local_addr)
# 接收数据
# udp_socket.sendto(b"haha",("192.168.220.1",8080))
udp_socket.close()
if __name__ =='__main__':
main() 21,1 Top
2.tcp实现
tcp分为客户端和服务器
1.tcp-client发送信息青春版
(1)先创建一个tcp套接字
tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
不同于udp,socket()函数的第二个参数里更改为SOCK_STREAM
(2)然后调用connect函数调用服务器,将服务器的ip地址个port端口以元组形式传进connect里
(3)接着进行收发信息操作:发信息用send函数
(4)最后关闭套接字
import socket
def main():
# 1创建tcp套接字
tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 2链接服务器
server_ip = input("请输入需要连接的服务器的ip:")
server_port = int(input("请输入此服务器的port:"))
server_addr = (server_ip,server_port)
tcp_socket.connect(server_addr)
# 3发送/接收数据
send_data = input("请输入要发送的信息:")
tcp_socket.send(send_data.encode("utf-8"))
# 4关闭套接字
tcp_socket.close()
if __name__ == '__main__':
main()
2.tcp-server青春版
(1)创建套接字
(2)绑定本地port,因为是服务器所以要帮定
(3)调用listen(128)函数,是服务器处于被动状态,128可以理解为最多有128个客户端链接
(4)等待客户端的链接,调用accept()函数,会有两个返回值,第一个表示客户端的套接字,第二个是客户端的地址信息
(5)调用recv(1024)接受信息1024是最大字节数
(6)调用send()回信息,告诉客户端链接成功
(7)关闭套接字,先关闭客户端的套接字,然后是服务器的套接字
import socket
def main():
# 1 买个手机 (创建套接字)
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 2 插个手机卡 (绑定本地信息 bind)
tcp_server_socket.bind(("",7890))
# 3 将手机设置为响铃模式(让默认的套接字由主动变为被动listen)
tcp_server_socket.listen(128)
# 4 等待别人打电话 (等待客户端的链接accept)
print("-----1-----")
new_client_socket,client_addr = tcp_server_socket.accept()
print("-----2-----")
print(client_addr)
# 接受客户短发送过来的请求
recv_data = new_client_socket.recv(1024)
print(recv_data)
# 回送一部分数据给客户端
new_client_socket.send("hhhhhh-----ok------".encode('utf-8'))
# 关闭套接字
new_client_socket.close()
tcp_server_socket.close()
if __name__ == "__main__":
main()
3.循环为多个客户端服务的服务器青春版
(1)创建套接字
(2)绑定ip和port ip一般用空字符串表示
(3)调用listen
(4)进入循环,accept循环接受客户端的链接,客户端的套接字关闭也要在循环里
(5)关闭服务器的套接字
import socket
def main():
# 创建套接字
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 绑定ip 和 port
tcp_server_socket.bind(("",4111))
# 被动接受数据
tcp_server_socket.listen(128)
while True:
print("-----1-----\n等待一个客户端到来")
# 接收数据
new_client_socket,client_addr = tcp_server_socket.accept()
print("-----2-----\n客户端来喽")
print(f"地址为:{client_addr}")
# 读取信息
recv_data = new_client_socket.recv(1024)
# 回送信息给客户端
print(f"信息是:{recv_data}")
new_client_socket.send("----给我成功----".encode('utf-8'))
# 关闭套接字
new_client_socket.close()
print("服务结束")
tcp_server_socket.close()
if __name__ == "__main__":
main()
~
4.升级版的循环服务的服务器
大体步骤和3类似,循环体内又加了一个循环,recv_data = new_cilent_socket.recv(1024)
为空时,表示客户端断开链接,升级版可以一直接收一个客户端的信息。
import socket
def main():
# 创建套接字
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 绑定ip 和 port
tcp_server_socket.bind(("",4111))
# 被动接受数据
tcp_server_socket.listen(128)
while True:
print("-----1-----\n等待一个客户端到来")
# 接收数据
new_client_socket,client_addr = tcp_server_socket.accept()
print("-----2-----\n客户端来喽")
print(f"地址为:{client_addr}")
while True:
# 读取信息
recv_data = new_client_socket.recv(1024)
# 回送信息给客户端
print(f"客户端的请求是:{recv_data}")
if recv_data:
new_client_socket.send("----给我成功----".encode('utf-8'))
else:break
# 关闭套接字
new_client_socket.close()
print("服务结束")
tcp_server_socket.close()
if __name__ == "__main__":
main()
5.案例-文件下载器
先是客户端
(1)创建套接字。。。。。。。。到第四步
(4)获取文件的名字
(5)将文件的名字发送到服务器里
(6)等待服务器响应
(7)移步服务器
import socket
def main():
# 1.创建套接字
tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 2.获取服务器ip port
dest_ip = input("请输入下载服务器的ip:")
dest_port = int(input("请输入下载服务器的port:"))
# 3.链接服务器
tcp_socket.connect((dest_ip,dest_port))
# 4.获取下载的文件名称
download_file_name = input("请输入要下载的文件名字:")
# 5.将文件名字发送到服务器
tcp_socket.send(download_file_name.encode("utf-8"))
# 6.接收文件中的数据
recv_data = tcp_socket.recv(1024) # 1024 * 1024 = 1M
if recv_data:
# 7.保存接收到的数据到一个文件中
with open("[新]" + download_file_name,'wb') as f:
f.write(recv_data)
else:print("没有要下载的文件:")
# 8.关闭套接字
tcp_socket.close()
if __name__ == "__main__":
main()
~
~
服务器:
循环体内等待客户端链接,接收到一个客户端,send_file_2_client里接收服务器名字,先把文件内容定义为空,try内,打开文件,如果没有要下载的文件就打印结果,最后if 内,如果有文件就将内容发送给客户端,客户端接收到内容,就创建一个文件并将内容写入,否则print("没有要下载的文件"),最后关闭套接字
import socket
def send_file_2_client(new_client_socket,client_addr):
# 读取信息
# 1.接受客户端需要的文件名
file_name = new_client_socket.recv(1024).decode('utf-8')
file_content = None
# 2.打开这个文件,读取数据
try:
f = open(file_name,'rb')
file_content = f.read()
f.close()
except Exception as ret:
print("没有要下载的文件(%s)" % file_name)
# 3.发送文件的数据给客户端
if file_content:
print(f"客户端{client_addr}需要下载的文件是:{file_name}")
new_client_socket.send(file_content)
def main():
# 创建套接字
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 绑定ip 和 port
tcp_server_socket.bind(("",4111))
# 被动接受数据
tcp_server_socket.listen(124)
while True:
# 接收数据
new_client_socket,client_addr = tcp_server_socket.accept()
print(f"地址为:{client_addr}")
# 调用函数完成服务
send_file_2_client(new_client_socket,client_addr)
# 关闭套接字
new_client_socket.close()
tcp_server_socket.close()
if __name__ == "__main__":
main()
~
二.多任务
1.多任务(线程实现)
1.多任务-线程
定义两个函数sing和dance
通过导入模块threading
里面有个类Thread()有两个参数,第一个表示目标函数,第二个表示函数的参数,用元组表示
创建对象后调用start来实现两个函数并发执行
import time
import threading
def sing():
'''正在唱歌'''
for i in range(5):
print("-----正在唱歌-----")
time.sleep(1)
def dance():
'''正在跳舞'''
for i in range(10):
print('-----正在跳舞-----')
time.sleep(1)
def main():
t1 = threading.Thread(target = sing)
t2 = threading.Thread(target = dance)
t1.start()
t2.start()
while True:
# 查看线程数
print(threading.enumerate())
if len(threading.enumerate()) == 1:break
time.sleep(1)
if __name__ == "__main__":
main()
~
~
2.继承Thread类完成多任务
import threading
import time
class Mythread(threading.Thread):
def run(self):
self.login()
self.register()
for i in range(3):
time.sleep(1)
msg = "I'm" + self.name + ' @ ' +str(i)
print(msg)
def login(self):
for i in range(5):
print("正在等录" + str(i))
time.sleep(1)
def register(self):
for i in range(10):
print("正在注册" + str(i))
time.sleep(1)
if __name__ == "__main__":
t = Mythread()
t.start()
~
3.函数里修改全局变量
调用threading的方法,多线程之间共享全局变量
import threading
import time
nums = [11,22,33]
def test1(temp):
temp.append(44)
print(f"{temp}")
def test2(temp):
temp.append(44)
print(temp)
if __name__ == "__main__":
t1 = threading.Thread(target = test1,args = (nums,))
t2 = threading.Thread(target = test2,args = (nums,))
t2.start()
t1.start()
4.互斥锁解决资源竞争问题
使用多线程对全局变量进行修改时,如果调用次数很多,会产生资源竞争问题,
可以定义一个互斥锁mutex = threading.Lock()
acquire表示上锁,release表示解锁
上锁到解锁之间只允许一个线程运行
import time
import threading
g_num = 0
mutex = threading.Lock()
def test1(num):
global g_num
mutex.acquire()
for i in range(num):
g_num += 1
mutex.release()
print("----------in test1 g_num = %d----------" % g_num)
def test2(num):
global g_num
mutex.acquire()
for i in range(num):
g_num += 1
mutex.release()
print("----------in test2 g_num = %d----------" % g_num)
def main():
t1 = threading.Thread(target = test1,args = (1000000,))
t2 = threading.Thread(target = test2,args = (1000000,))
t1.start()
t2.start()
time.sleep(5)
print("----------in main g_num = %d----------" % g_num)
if __name__ == "__main__":
main()
5.多任务实现udp聊天器
定义两个函数,一个接收信息,一个发送信息,之前的聊天器很死板,只能发一次收一次,有了多任务,就可以实现收发一起执行,不一样的是,最后不能关闭套接字,因为不知到什么时候聊天结束。
import socket
import threading
def recv_meassage(udp_socket):
'''接收信息并显示'''
while True:
recv_data = udp_socket.recvfrom(1024)
recv_msg = recv_data[0].decode('utf-8')
recv_addr = recv_data[1]
print(f"\n{recv_addr}发来了信息:{recv_msg}")
def send_msg(udp_socket ,dest_ip, dest_port):
'''发送信息'''
while True:
send_data = input("请输入您要发送的信息:")
udp_socket.sendto(send_data.encode('utf-8'), (dest_ip, dest_port))
def main():
# 创建套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定端口
udp_socket.bind(('',3555))
dest_ip = input("请输入对方的ip地址:")
dest_port = int(input("请输入对方ip地址的端口port:"))
t_send = threading.Thread(target = send_msg, args = (udp_socket, dest_ip, dest_port))
t_recv = threading.Thread(target = recv_meassage, args = (udp_socket,))
t_send.start()
t_recv.start()
# 关闭套接字
# udp_socket.close()
if __name__ == "__main__":
main()
————————————————
版权声明:本文为CSDN博主「小白来巡山^_^」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:
1.多任务(进程实现)
1.使用进程完成多任务
与线程类似,进程实现多任务需要导入模块 multiprocessing
不过,进程之间不共享全局变量,Process这个类和Thread一样,大致流程与线程实现多任务类似。
import time
import multiprocessing
num = 0
def test1(n):
global num
for i in range(n):
num += 1
print(f"1------{i}------")
def test2(n):
global num
for i in range(n):
num += 1
print(f"2-----{i}-----")
def main():
p1 = multiprocessing.Process(target = test1, args = (100,))
p2 = multiprocessing.Process(target = test2, args = (200,))
p1.start()
p2.start()
time.sleep(10)
print(num)
if __name__ == "__main__":
main()
2.利用队列完成多任务进程之间的通信
需要创建一个实例对象q = multiprocessing.Queue()
并把q当作参数传进需要完成通信的子进程中去,队列是先进先出,向队列传数据用put,取数据用get,可以用p.empty()判断队列是否为空,p.full()判断队列是否满
import multiprocessing
def download_from_web(q):
'''下载数据'''
data = [11,22,33,44]
#相队列中写入数据
for temp in data:
q.put(temp)
print(f'{data}-----下载器已经下载完了数据并存入到队列中-----')
def analysis_data(q):
'''数据处理'''
# 从队列中获取数据病并模拟处理
waitting_analysis_data = list()
while True:
data = q.get()
waitting_analysis_data.append(data)
if q.empty():break
print(waitting_analysis_data)
def main():
# 1.创建一个队列
q = multiprocessing.Queue()
p1 = multiprocessing.Process(target = download_from_web, args = (q,))
p2 = multiprocessing.Process(target = analysis_data ,args = (q,))
p1.start()
p2.start()
if __name__ =="__main__":
main()
3.案例-复制文件jia里所有文件青春版
用到了os模块里的mkdir创建文件夹,参数为文件夹的名字
os.listdir()获取名称为参数名称的文件夹里的所有文件名称,返回值是一个列表
引入新东西,进程池
po = multiprocessing.Pool(5)
参数表示一个进程池里最多可yi容纳五个进程
调用方法po.apply_async(copy_file ,args = (''''''''))向进程池里传入进程
close()关闭
join()让进程池里的进程执行完
函数里面 显示读取文件里的内容,再把内容写进新文件夹里文件里,完成拷贝
import os
import multiprocessing
def copy_file(file_name, new_folder_name, old_folder_name):
print(file_name)
f1 = open(old_folder_name + '/' + file_name, 'rb')
f_content = f1.read()
f1.close()
f2 = open(new_folder_name + '/' + file_name,'wb')
f2.write(f_content)
f2.close()
def main():
# 获取要下载的文件夹的名字
old_folder_name = input("请输入要复制的文件夹的名字:")
# 创建一个新的文件夹
new_folder_name = old_folder_name + "[复件]"
try:
os.mkdir(new_folder_name)
except:pass
# 获取文件夹里所有文件的名字
file_names = os.listdir(old_folder_name)
# 创建进程池
po = multiprocessing.Pool(5)
# 向进程chi里添加copy文件的任务
for file_name in file_names:
po.apply_async(copy_file, args = (file_name, new_folder_name, old_folder_name))
po.close()
po.join()
# 复制原文件夹的文件,到新文件夹里去
if __name__ == "__main__":
main()
4.案例-带进度条的文件夹拷贝器
要想实现进度条,实现主进程和子进程之间的通信,要用到队列,multiprocessing.Manager().Queue(),将队列以参数形式传入函数里,没下载好一个文件就put以下,主进程里,每get一下就输出一个进度,进度值为下载好的文件数除以总的文件数,不用调用join()因为循环一定能保证子进程执行完毕,最后break
mport os
import multiprocessing
def copy_file(q, file_name, new_folder_name, old_folder_name):
# print(file_name)
f1 = open(old_folder_name + '/' + file_name, 'rb')
f_content = f1.read()
f1.close()
f2 = open(new_folder_name + '/' + file_name, 'wb')
f2.write(f_content)
f2.close()
# 如果拷贝完了队列就像队列中写入消息
q.put(file_name)
def main():
# 获取要下载的文件夹的名字
old_folder_name = input("请输入要复制的文件夹的名字:")
# 创建一个新的文件夹
new_folder_name = old_folder_name + "[复件]"
try:
os.mkdir(new_folder_name)
except:pass
# 获取文件夹里所有文件的名字
file_names = os.listdir(old_folder_name)
# 创建进程池
po = multiprocessing.Pool(5)
# 创建队列
q = multiprocessing.Manager().Queue()
# 向进程chi里添加copy文件的任务
for file_name in file_names:
po.apply_async(copy_file, args = (q, file_name, new_folder_name, old_folder_name))
po.close()
# po.join()
all_file_num = len(file_names)
now_file_num = 0
while True:
q.get()
now_file_num += 1
print('拷贝进度:%.2f%%' % (now_file_num * 100 / all_file_num))
if now_file_num >= all_file_num:break
# 复制原文件夹的文件,到新文件夹里去
if __name__ == "__main__":
main()
3.多任务(协程实现)
1.迭代器-自己定义的类进行迭代青春版
from collections import Iterable,Iterator
import time
class Classmate(object):
def __init__(self):
self.names = list()
def add(self,name):
self.names.append(name)
def __iter__(self):
return ClassIterator(self)
class ClassIterator():
def __init__(self,obj):
self.obj = obj
def __iter__(self):
pass
def __next__(self):
return self.obj.names[0]
classmate = Classmate()
classmate.add('张三')
classmate.add('李四')
classmate.add('王五')
# print("判断classmate是否是可以迭代的对象:", isinstance(classmate, Iterable))
# classmate_iterator = iter(classmate)
# print("判断classmate_iterator是否是迭代器:", isinstance(classmate_iterator, Iterator))
# print(next(classmate_iterator))
for temp in classmate:
print(temp)
time.sleep(1)
~
2.迭代器-自己的类进行迭代
将Classmate类里添加 __iter__ 和 __next__类 完成迭代器
from collections.abc import Iterable,Iterator
import time
class Classmate(object):
def __init__(self):
self.names = list()
self.current_num = 0
def add(self,name):
self.names.append(name)
def __iter__(self):
return self
def __next__(self):
if self.current_num < len(self.names):
ret = self.names[self.current_num]
self.current_num += 1
return ret
else:
raise StopIteration
classmate = Classmate()
classmate.add('张三')
classmate.add('李四')
classmate.add('王五')
# print("判断classmate是否是可以迭代的对象:", isinstance(classmate, Iterable))
# classmate_iterator = iter(classmate)
# print("判断classmate_iterator是否是迭代器:", isinstance(classmate_iterator, Iterator))
# print(next(classmate_iterator))
for temp in classmate:
print(temp)
time.sleep(1)
~
~
3.迭代器实现多任务(Fibonacci为例子)
迭代器的优点:相对于list()创建列表,迭代器占用的内存非常小
class Fibonacci():
def __init__(self,all_num):
self.all_num = all_num
self.a = 0
self.b = 1
self.current_num = 0
def __iter__(self):
return self
def __next__(self):
if self.all_num > self.current_num:
ret = self.a
self.a ,self.b = self.b, self.a + self.b
self.current_num += 1
return ret
else:raise StopIteration
f = Fibonacci(10)
for num in f:
print(num)
4.生成器-实现斐波那契数列
在函数里只要有yield就不是函数了,是生成器,创建对象obj,调用next(obj)调取a的值
def create_num(all_num):
print('------1------')
a, b = 0, 1
current_num = 0
while current_num < all_num:
print('------2------')
yield a
# print(a)
print('------3------')
a, b = b, a + b
current_num += 1
# 如果函数有一个yield语句,这个函数就不是函数了,成为了一个生成器的模板,调用create_num时,生成器是一种特殊的迭代器,创建了一个生成器的对象
obj = create_num(10)
ret = next(obj)
print(ret)
ret = next(obj)
print(ret)
# for i in obj:
# print(i)
~
~
5.生成器的一些知识
循环读取数据,当读不出来是,抛出一场 e.value为生成器的返回值
def create_num(all_num):
print('------1------')
a, b = 0, 1
current_num = 0
while current_num < all_num:
print('------2------')
yield a
# print(a)
print('------3------')
a, b = b, a + b
current_num += 1
return 'ok------ok'
# 如果函数有一个yield语句,这个函数就不是函数了,成为了一个生成器的模板,调用create_num时,生成器是一种特殊的迭代器,创建了一个生成器的对象
obj = create_num(10)
while True:
try:
ret = next(obj)
print(ret)
except Exception as e:
print(e.value)
break
# for i in obj:
# print(i)
6.生成器send()实现多任务
send和next差不多,但是 通过向send传参数, ret = yield a可以收到参数值
def create_num(all_num):
print('------1------')
a, b = 0, 1
current_num = 0
while current_num < all_num:
print('------2------')
ret = yield a
print("ret:",ret)
# print(a)
print('------3------')
a, b = b, a + b
current_num += 1
return 'ok------ok'
# 如果函数有一个yield语句,这个函数就不是函数了,成为了一个生成器的模板,调用create_num时,生成器是一种特殊的迭代器,创建了一个生成器的对象
obj = create_num(10)
ret = next(obj)
print(ret)
ret = obj.send('wocaowocaowocao')
print(ret)
# for i in obj:
# print(i)
~
~
7.通过yield完成多任务
看看就能懂
import time
def test1():
while True:
print("-----1-----")
time.sleep(0.1)
yield
def test2():
while True:
print("-----2-----")
time.sleep(0.1)
yield
def main():
t1 = test1()
t2 = test2()
while True:
next(t1)
next(t2)
if __name__ == "__main__":
main()
~
~
8.greenlet多任务
调用实例对象后,在两个函数里switch()完成多任务,并发执行
from greenlet import greenlet
import time
def test1():
while True:
print("-----1-----")
gr2.switch()
time.sleep(0.5)
def test2():
while True:
print("-----2-----")
gr1.switch()
time.sleep(0.5)
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
9.gevent完成多任务
这个不常用
import gevent
import time
def f(n):
for i in range(n):
print(gevent.getcurrent(),i)
# time.sleep(0.5)
gevent.sleep(0.5)
# ( 函数名,参数)
g1 = gevent.spawn(f,5)
g2 = gevent.spawn(f,5)
g3 = gevent.spawn(f,5)
# join遇到了延时,等待g1运行完,延时时还能执行其他的
g1.join()
g2.join()
g3.join()
10.gevent多任务-2
这个常用
import gevent
import time
from gevent import monkey
# 打补丁:把当前代码所有耗时的代码换成gevent
monkey.patch_all()
def f(n):
for i in range(n):
print(gevent.getcurrent(),i)
time.sleep(0.5)
# gevent.sleep(0.5)
# ( 函数名,参数)
# g1 = gevent.spawn(f,5)
# g2 = gevent.spawn(f,5)
# g3 = gevent.spawn(f,5)
# join遇到了延时,等待g1运行完,延时时还能执行其他的
# g1.join()
# g2.join()
# g3.join()
# joinall更常用
gevent.joinall([gevent.spawn(f,5),gevent.spawn(f,5),gevent.spawn(f,5)])
11.案例-图片下载器
看看就懂
import urllib.request
import gevent
from gevent import monkey
monkey.patch_all()
def downloader(img_name, img_url):
req = urllib.request.urlopen(img_url)
img_content = req.read()
with open(img_name, "wb") as f:
f.write(img_content)
def main():
gevent.joinall([
gevent.spawn(downloader, '3.jpg', 'https://rpic.douyucdn.cn/live-cover/roomCover/2022/01/14/39e88aa4a2576eb6f0b64b71aa7730ef_big.png/dy1'),
gevent.spawn(downloader, '4.jpg', 'http://i2.hdslb.com/bfs/archive/9cbd84d68b1ebe28e39229cbe02ce7f54e8c2365.jpg@672w_378h_1c')
])
if __name__ == "__main__":
main()
三.web服务器v3.1
1.正则表达式简介
直接上案例
1.正则判断变量名是否合理
import re
def main():
while True:
name = input("请输入变量名称:(输入quit退出)")
# match自动判断开头
# ret = re.match(r"[a-zA-Z_][a-zA-Z_0-9]*$",name)
ret = re.match(r"^[a-zA-Z_][a-zA-Z_0-9]*$",name)
if name == 'quit':break
elif ret:print("成功%s" %ret.group())
else:print("失败喽!")
if __name__ == "__main__":
main()
2.正则判断常用邮箱地址
import re
def main():
while True:
email_name = input("请输入变量名称:(输入quit退出)")
# match自动判断开头,\使需要的特殊字符转义
ret = re.match(r"^[a-zA-Z_0-9]{4,20}@(163|126|qq|gmail)\.com$",email_name)
if email_name == 'quit':break
elif ret:print("成功%s" %ret.group())
else:print("失败喽!")
if __name__ == "__main__":
main()
2.http
1.实现简单的http服务器
浏览器相当于客户端,向服务器提出请求
服务器回送浏览器需要的数据
import socket
def service_client(new_socket):
'''为这个客户端返回数据'''
# 接受浏览器发送的请求(http请求)
request = new_socket.recv(1024)
print(request)
# 返回http格式的数据给浏览器
# 准备发送给浏览器的数据 -----header \r\n表示浏览器可以识别的换行
response = "HTTP/1.1 200 OK\r\n"
response += "\r\n"
# 准备发送给浏览器的数据 -----body
response += "<h1>this is a test.</h1>"
new_socket.send(response.encode("utf-8"))
#关闭
new_socket.close()
def main():
# 创建套接字
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 绑定
tcp_server_socket.bind(("",7890))
# 变为监听套接字
tcp_server_socket.listen(128)
while True:
# 等待客户链接
new_socket, client_addr = tcp_server_socket.accept()
# 服务
service_client(new_socket)
# 关闭
tcp_server_socket.close()
if __name__ == "__main__":
main()
2.根据客户端需要完成http服务器
import socket
def service_client(new_socket):
'''为这个客户端返回数据'''
# 接受浏览器发送的请求(http请求)
request = new_socket.recv(1024)
print(request)
print(">>>>>>>>>>" * 4) # 返回http格式的数据给浏览器
# 准备发送给浏览器的数据 -----header \r\n表示浏览器可以识别的换行
response = "HTTP/1.1 200 OK\r\n"
response += "\r\n"
# 准备发送给浏览器的数据 -----body
# response += "<h1>this is a test.</h1>"
with open("./html/index.html",'rb') as f:
f_content = f.read()
new_socket.send(response.encode("utf-8"))
new_socket.send(f_content)
#关闭
new_socket.close()
def main():
# 创建套接字
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 重复利用同一个端口
tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 绑定
tcp_server_socket.bind(("",7890))
# 变为监听套接字
tcp_server_socket.listen(128)
while True:
# 等待客户链接
new_socket, client_addr = tcp_server_socket.accept()
# 服务
service_client(new_socket)
# 关闭
tcp_server_socket.close()
if __name__ == "__main__":
main()
3.返回index页面http
import socket
import re
def service_client(new_socket):
'''为这个客户端返回数据'''
# 接受浏览器发送的请求(http请求)
request = new_socket.recv(1024).decode('utf-8')
# print(request)
# print(">>>>>>>>>>" * 4) # 返回http格式的数据给浏览器
request_lines = request.splitlines()
print("")
print(">" * 20)
print(request_lines)
file_name = ''
ret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])
if ret:
file_name = ret.group(1)
# print("*" * 50, file_name)
if file_name == '/':file_name = '/index.html'
# 准备发送给浏览器的数据 -----body
# response += "<h1>this is a test.</h1>"
try:
with open("./html" + file_name, 'rb') as f:
f_content = f.read()
except:
response = "HTTP/1.1 404 NOT FOUND\r\n"
response += "\r\n"
response += "-----file not found-----"
new_socket.send(response.encode('utf-8'))
else:
# 准备发送给浏览器的数据 -----header \r\n表示浏览器可以识别的换行
response = "HTTP/1.1 200 OK\r\n"
response += "\r\n"
new_socket.send(response.encode("utf-8"))
new_socket.send(f_content)
#关闭
new_socket.close()
def main():
# 创建套接字
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 重复利用同一个端口
tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 绑定
tcp_server_socket.bind(("",7890))
# 变为监听套接字
tcp_server_socket.listen(128)
while True:
# 等待客户链接
new_socket, client_addr = tcp_server_socket.accept()
# 服务
service_client(new_socket)
# 关闭
tcp_server_socket.close()
if __name__ == "__main__":
main()
4.使用多进程完成http服务器
import multiprocessing
import socket
import re
def service_client(new_socket):
'''为这个客户端返回数据'''
# 接受浏览器发送的请求(http请求)
request = new_socket.recv(1024).decode('utf-8')
# print(request)
# print(">>>>>>>>>>" * 4) # 返回http格式的数据给浏览器
request_lines = request.splitlines()
print("")
print(">" * 20)
print(request_lines)
file_name = ''
ret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])
if ret:
file_name = ret.group(1)
# print("*" * 50, file_name)
if file_name == '/':file_name = '/index.html'
# 准备发送给浏览器的数据 -----body
# response += "<h1>this is a test.</h1>"
try:
with open("./html" + file_name, 'rb') as f:
f_content = f.read()
except:
response = "HTTP/1.1 404 NOT FOUND\r\n"
response += "\r\n"
response += "-----file not found-----"
new_socket.send(response.encode('utf-8'))
else:
# 准备发送给浏览器的数据 -----header \r\n表示浏览器可以识别的换行
response = "HTTP/1.1 200 OK\r\n"
response += "\r\n"
new_socket.send(response.encode("utf-8"))
new_socket.send(f_content)
#关闭
new_socket.close()
def main():
# 创建套接字
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 重复利用同一个端口
tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 绑定
tcp_server_socket.bind(("",7777))
# 变为监听套接字
tcp_server_socket.listen(128)
while True:
# 等待客户链接
new_socket, client_addr = tcp_server_socket.accept()
# 服务
p = multiprocessing.Process(target = service_client, args = (new_socket,))
p.start()
new_socket.close()
# 关闭
tcp_server_socket.close()
if __name__ == "__main__":
main()
5.使用多线程完成http
import threading
import socket
import re
def service_client(new_socket):
'''为这个客户端返回数据'''
# 接受浏览器发送的请求(http请求)
request = new_socket.recv(1024).decode('utf-8')
# print(request)
# print(">>>>>>>>>>" * 4) # 返回http格式的数据给浏览器
request_lines = request.splitlines()
print("")
print(">" * 20)
print(request_lines)
file_name = ''
ret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])
if ret:
file_name = ret.group(1)
# print("*" * 50, file_name)
if file_name == '/':file_name = '/index.html'
# 准备发送给浏览器的数据 -----body
# response += "<h1>this is a test.</h1>"
try:
with open("./html" + file_name, 'rb') as f:
f_content = f.read()
except:
response = "HTTP/1.1 404 NOT FOUND\r\n"
response += "\r\n"
response += "-----file not found-----"
new_socket.send(response.encode('utf-8'))
else:
# 准备发送给浏览器的数据 -----header \r\n表示浏览器可以识别的换行
response = "HTTP/1.1 200 OK\r\n"
response += "\r\n"
new_socket.send(response.encode("utf-8"))
new_socket.send(f_content)
#关闭
new_socket.close()
def main():
# 创建套接字
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 重复利用同一个端口
tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 绑定
tcp_server_socket.bind(("",7777))
# 变为监听套接字
tcp_server_socket.listen(128)
while True:
# 等待客户链接
new_socket, client_addr = tcp_server_socket.accept()
# 服务
t = threading.Thread(target = service_client, args = (new_socket,))
t.start()
# 多线程不需要所有的套接字都关闭
# new_socket.close()
# 关闭
tcp_server_socket.close()
if __name__ == "__main__":
main()
6.协程完成http服务器
import gevent
from gevent import monkey
import socket
import re
monkey.patch_all()
def service_client(new_socket):
'''为这个客户端返回数据'''
# 接受浏览器发送的请求(http请求)
request = new_socket.recv(1024).decode('utf-8')
# print(request)
# print(">>>>>>>>>>" * 4) # 返回http格式的数据给浏览器
request_lines = request.splitlines()
print("")
print(">" * 20)
print(request_lines)
file_name = ''
ret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])
if ret:
file_name = ret.group(1)
# print("*" * 50, file_name)
if file_name == '/':file_name = '/index.html'
# 准备发送给浏览器的数据 -----body
# response += "<h1>this is a test.</h1>"
try:
with open("./html" + file_name, 'rb') as f:
f_content = f.read()
except:
response = "HTTP/1.1 404 NOT FOUND\r\n"
response += "\r\n"
response += "-----file not found-----"
new_socket.send(response.encode('utf-8'))
else:
# 准备发送给浏览器的数据 -----header \r\n表示浏览器可以识别的换行
response = "HTTP/1.1 200 OK\r\n"
response += "\r\n"
new_socket.send(response.encode("utf-8"))
new_socket.send(f_content)
#关闭
new_socket.close()
def main():
# 创建套接字
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 重复利用同一个端口
tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 绑定
tcp_server_socket.bind(("",7777))
# 变为监听套接字
tcp_server_socket.listen(128)
while True:
# 等待客户链接
new_socket, client_addr = tcp_server_socket.accept()
# 服务
gevent.spawn(service_client, new_socket)
# 关闭
tcp_server_socket.close()
if __name__ == "__main__":
main()
7.单进程单线程非堵塞并发完成http服务器
import socket
def service_client(new_socket):
'''为这个客户端返回数据'''
# 接受浏览器发送的请求(http请求)
request = new_socket.recv(1024)
print(request)
print(">>>>>>>>>>" * 4) # 返回http格式的数据给浏览器
# 准备发送给浏览器的数据 -----header \r\n表示浏览器可以识别的换行
response = "HTTP/1.1 200 OK\r\n"
response += "\r\n"
# 准备发送给浏览器的数据 -----body
# response += "<h1>this is a test.</h1>"
with open("./html/index.html",'rb') as f:
f_content = f.read()
new_socket.send(response.encode("utf-8"))
new_socket.send(f_content)
#关闭
new_socket.close()
def main():
# 创建套接字
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 重复利用同一个端口
tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 绑定
tcp_server_socket.bind(("",7890))
# 变为监听套接字
tcp_server_socket.listen(128)
# 设置套接字为非堵塞的方式
tcp_server_socket.setblocking(False)
# 创建一个套接字列表
new_socket_list = list()
while True:
try:
# 等待客户链接
new_socket, client_addr = tcp_server_socket.accept()
except Exception as ret:
print("-----没有客户端到来-----")
else:
print("---客户端到来---")
new_socket.setblocking(False)
new_socket_list.append(new_socket)
for new_socket in new_socket_list:
try:
recv_data = new_socket.recv(1024)
except Exception as ret:
print("客户端没有发送数据")
else:
if recv_data:
# 对方发送了数据
print("接收到数据")
else:
# 对方调用了close()
new_socket_list.remove(new_socket)
new_socket.close()
# 服务
# service_client(new_socket)
# 关闭
tcp_server_socket.close()
if __name__ == "__main__":
main()
8.单进程单线程非堵塞长连接
import socket
import re
def service_client(new_socket, request):
'''为这个客户端返回数据'''
# 接受浏览器发送的请求(http请求)
# request = new_socket.recv(1024)
# print(request)
# print(">>>>>>>>>>" * 4) # 返回http格式的数据给浏览器
# 准备发送给浏览器的数据 -----header \r\n表示浏览器可以识别的换行
request_lines = request.splitlines()
print('')
print(">" * 20)
print(request_lines)
file_name = ''
ret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])
if ret:
file_name = ret.group(1)
if file_name == '/':
file_name = '/index.html'
# 准备发送给浏览器的数据 -----body
# response += "<h1>this is a test.</h1>"
try:
f = open("./html" + file_name, 'rb')
except:
response_body = "sorry,there are no file that you wanna."
response_header = "HTTP/1.1 404 NOT FOUND\r\n"
response_header += f'Content-Length:{len(response_body)}'
response_header += '\r\n'
response = response_header + response_body
new_socket.send(response.encode('utf-8'))
else:
f_content = f.read()
f.close()
response_body = f_content
response_header = "HTTP/1.1 200 OK\r\n"
response_header += 'Content-Length:%d\r\n' % len(response_body)
response_header += '\r\n'
response = response_header.encode('utf-8') + response_body
new_socket.send(response)
# 关闭
# new_socket.close()
def main():
# 创建套接字
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 重复利用同一个端口
tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 绑定
tcp_server_socket.bind(("",7890))
# 变为监听套接字
tcp_server_socket.listen(128)
# 非堵塞
tcp_server_socket.setblocking(False)
new_socket_list = list()
while True:
try:
# 等待客户链接
new_socket, client_addr = tcp_server_socket.accept()
except Exception as ret:
pass
else:
new_socket.setblocking(False)
new_socket_list.append(new_socket)
for client_socket in new_socket_list:
try:
recv_data = client_socket.recv(1024).decode('utf-8')
except Exception as ret:
pass
else:
if recv_data:
service_client(client_socket, recv_data)
else:
client_socket.close()
new_socket_list.remove(client_socket)
# 服务
# service_client(new_socket)
# 关闭
tcp_server_socket.close()
if __name__ == "__main__":
main()
9.epoll实现http服务器
import socket
import select
import re
def service_client(new_socket, request):
'''为这个客户端返回数据'''
# 接受浏览器发送的请求(http请求)
# request = new_socket.recv(1024)
# print(request)
# print(">>>>>>>>>>" * 4) # 返回http格式的数据给浏览器
# 准备发送给浏览器的数据 -----header \r\n表示浏览器可以识别的换行
request_lines = request.splitlines()
print('')
print(">" * 20)
print(request_lines)
file_name = ''
ret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])
if ret:
file_name = ret.group(1)
if file_name == '/':
file_name = '/index.html'
# 准备发送给浏览器的数据 -----body
# response += "<h1>this is a test.</h1>"
try:
f = open("./html" + file_name, 'rb')
except:
response_body = "sorry,there are no file that you wanna."
response_header = "HTTP/1.1 404 NOT FOUND\r\n"
response_header += f'Content-Length:{len(response_body)}'
response_header += '\r\n'
response = response_header + response_body
new_socket.send(response.encode('utf-8'))
else:
f_content = f.read()
f.close()
response_body = f_content
response_header = "HTTP/1.1 200 OK\r\n"
response_header += 'Content-Length:%d\r\n' % len(response_body)
response_header += '\r\n'
response = response_header.encode('utf-8') + response_body
new_socket.send(response)
# 关闭
# new_socket.close()
def main():
# 创建套接字
tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 重复利用同一个端口
tcp_server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
# 绑定
tcp_server_socket.bind(("",7777))
# 变为监听套接字
tcp_server_socket.listen(128)
# 非堵塞
tcp_server_socket.setblocking(False)
# 创建一个epoll对象
epl = select.epoll()
# 将监听套接字对应的fd注册到epoll中
epl.register(tcp_server_socket.fileno(), select.EPOLLIN)
fd_event_dict = dict()
while True:
fd_event_list = epl.poll() # 默认会堵塞,直到 os监测到数据到来 通过事件通知方式 告诉这个程序,此时才会解堵塞
# [(df, event), (套接字对应的文件描述符,描述符到底是什么时间例如调用recv接收等)]
for fd, event in fd_event_list:
# 等待新客户端的链接
if fd == tcp_server_socket.fileno():
new_socket, client_addr = tcp_server_socket.accept()
epl.register(new_socket.fileno(), select.EPOLLIN)
fd_event_dict[new_socket.fileno()] = new_socket
elif event == select.EPOLLIN:
# 判断已经链接的客户端是否有数据发送过来
recv_data = fd_event_dict[fd].recv(1024).decode('utf-8')
if recv_data:
service_client(fd_event_dict[fd], recv_data)
else:
fd_event_dict[fd].close()
epl.unregister(fd)
del fd_event_dict[fd]
# 服务
# service_client(new_socket)
# 关闭
tcp_server_socket.close()
if __name__ == "__main__":
main()