PythonThread_09_bj

前情回顾

线程

线程间的通信 ---》 全局变量
线程间同步互斥 ---》 Event  Lock
Python线程的GIL  ---》 Python中线程效率的低下

进程和线程 区别和联系, 使用情况

服务器:循环服务器
同一时刻中能有一个客户端占有服务器

    并发服务器
		IO并发  
			io多路复用 : 不希望IO长时间阻塞
							 
		多进程多线程并发
			多进程 : 资源的消耗较多
			多线程

多进程并发编程

fork tcp : 当有一个客户端连接则创建一个新的进程
为其服务,父进程继续等待接收新的客户
端连接请求

文件服务器


cookie

文件处理函数

os.listdir(PATH) : 获取一个目录内文件列表

os.path.isfile() :判断一个文件的类型是否为普通文件
os.path.isdir() :判断一个文件的类型是否为目录

threading 的多线程并发

对比多进程并发:
优点 : 资源消耗少
缺点 : 需要注意共享该资源的争夺
Python多线程收到GIL的影响

实现步骤:

  1. 创建套接字,绑定,监听
  2. 接收客户端连接请求,创建新的线程
  3. 主线程继续等待其他客户端连接,分支线程执行客户端请求
  4. 处理完客户端请求后,分支线程退出,关闭客户端套接字

#01_thread_server.py

from socket import *
from threading import Thread
import sys

HOST = ‘0.0.0.0’
PORT = 8888
ADDR = (HOST,PORT)

def client_handle©:
print(“Connect from”,c.getpeername())
while True:
data = c.recv(1024).decode()
if not data:
break
print(data)
c.send(b"Receive your message")
c.close()

#创建tcp套接字
s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(ADDR)
s.listen()

while True:
try:
c,addr = s.accept()
except KeyboardInterrupt:
s.close()
sys.exit(“服务器退出”)
except Exception as e:
print(e)
continue

#创建线程,绑定函数执行具体客户端请求
t = Thread(target = client_handle,args = (c,))
t.setDaemon(True)
t.start()

socket服务器集成模块

python2 SocketServer
python3 socketserver

功能 : 通过模块的接口完成基于多进程/多线程的
tcp/udp 的socket并发程序

模块类

DatagramRequestHandler 处理udp请求
StreamRequestHandler 处理tcp请求

UDPServer 提供udp服务端类
TCPServer 提供tcp服务端类

ForkingMixIn 提供进程创建
ForkingTCPServer ==》ForkingMixIn + TCPServer
ForkingUDPServer ==》ForkingMixIn + UDPServer

ThreadingMixIn 提供线程创建
ThreadingTCPServer ==》ThreadingMixIn + TCPServer
ThreadingUDPServer ==》ThreadingMixIn + TCPServer

02_sock_server.py

from socketserver import *

创建多进程 tcp 并发

创建进程tcp服务器类

class Server(ForkingTCPServer):

class Server(ForkingMixIn,TCPServer):

# pass 

#多线程tcp并发
class Server(ThreadingTCPServer):
pass

#具体请求处理类
class Handler(StreamRequestHandler):
def handle(self):
#self.request 相当于accept创建的套接字
print(“Connect from”,self.request.getpeername())
while True:
data = self.request.recv(1024).decode()
if not data:
break
print(data)
self.request.send(b"Receive your message")

#生产服务器对象,传入addr和具体处理类
server = Server((“0.0.0.0”,8888),Handler)

#启动服务器
server.serve_forever()

03_sock_server1.py

from socketserver import *

#多进程 udp并发
class Server(ForkingMixIn,UDPServer):
pass

class Handler(DatagramRequestHandler):
def handle(self):
while True:
#接收消息
data = self.rfile.readline().decode()
if not data:
break
print(data)
#发送消息
self.wfile.write
(b"Receive your message")

server = Server((‘127.0.0.1’,8888),Handler)
server.serve_forever()

基于多线程并发的 HTTPServer

HTTPServer的作用

1.就收浏览器发送的http请求
2.对http请求进行解析
3.组织响应内容进行回发

升级

  • 使用多线程的并发可以同时处理多个客户端请求
  • 增加简单的应用程序,使浏览器不仅可以访问静态网页
    也可以访问后台程序
  • 使用类对服务器功能模块进行封装

技术点 : threading 并发
tcp socket 套接字
http协议响应内容进行字符串拼接

#04_HttpServer.py

‘’’
http server 第二版
‘’’
from socket import *
from threading import Thread
import time

ADDR = (‘0.0.0.0’,8000)
#存放静态页面的目录
STATIC_DIR = “./static”

#httpserver类 封装服务器功能
class HTTPServer(object):
def init(self,addr):
#套接字创建
self.sockfd = socket()
self.sockfd.setsockopt
(SOL_SOCKET,SO_REUSEADDR,1)
self.sockfd.bind(addr)
self.sockfd.listen(5)
#为对象添加一些属性
self.name = “HttpServer”
self.port = 8000
self.address = addr

# 监听客户端的链接请求,创建新的线程处理
def serve_forever(self):
    print("Listen to port 8000.....")
    while True:
        connfd,addr = self.sockfd.accept()
        #创建新的线程处理具体请求
        clientThread = \
        Thread(target = self.handleRequest,\
            args = (connfd,))

        clientThread.setDaemon(True)
        clientThread.start()

def handleRequest(self,connfd):
    #接收客户端请求
    request = connfd.recv(4096)
    requestHeadlers = request.splitlines()
    #请求行
    print(connfd.getpeername(),":",\
        requestHeadlers[0])
    #获取具体请求
    getRequest = \
    str(requestHeadlers[0]).split(' ')[1]

    #访问静态网页
    if getRequest[-3:] != ".py":
        if getRequest == '/':
            getFilename = STATIC_DIR + "/index.html"
        else:
            getFilename = STATIC_DIR + getRequest

        try:
            f = open(getFilename)
        except Exception:
            #没有找到页面
            responseHeaders = "HTTP/1.1 404 not found\r\n"
            responseHeaders += "\r\n"
            responseBody = "===Sorry,the page not found==="
        else:
            responseHeaders = "HTTP/1.1 200 OK\r\n"
            responseHeaders += "\r\n"
            responseBody = f.read()
        finally:
            response = responseHeaders + responseBody
            connfd.send(response.encode())
    #访问后台程序
    else:
        #通过函数得到响应体
        responseBody = self.application()

        responseHeaders = "HTTP/1.1 200 OK\r\n"
        responseHeaders += "\r\n"
        response = responseHeaders + responseBody

        connfd.send(response.encode())

    connfd.close()

#获取去你要使用的外部函数,变为属性
def setApp(self,application):
    self.application = application 

#后台程序
def app():
return “\n=假设这是一个很复杂的程序,你得到了一个很牛逼的内容=\n%s”%time.ctime()

if name == “main”:
httpd = HTTPServer(ADDR)
httpd.setApp(app)
#启动服务器
httpd.serve_forever()

协程

定义: 纤程 微线程 ,协程本质只有一个线程在运行

功能原理 : 通过应用层程序,记录上下文栈区,实现在程序执行过程中
的跳跃,选择可以不阻塞的部分执行,从而提高IO的执行效率

优点 : 资源消耗很少
无需多线程那样来回切换的开销
无需进行同步互斥操作
IO并发性好

缺点 : 无法利用计算机的多核资源
程序不能够一个客户端单独长时间占有服务端

yield–》 协程的基本实现关键字

sudo pip3 install greenlet
sudo pip3 install gevent

greenlet
greenlet.greenlet()
gr.switch()

05_greenlet1.py

def test1():
print(12)
gr2.switch()
print(34)
gr2.switch()

def test2():
print(56)
gr1.switch()
print(78)

#协程对象
gr1 = greenlet(test1)
gr2 = greenlet(test2)

#调用协程函数
gr1.switch()

12

56

34

78

gevent

  • 将协程事件封装为函数

gevent.spawn(func,argv)
功能 : 将事件变为协程事件并启动
参数 : func 传入一个函数变为协程
argv 给func函数传参
返回值 : 协程对象

gevent.joinall()
功能:回收协程

gevent.sleep(n)
功能 ; 模拟IO阻塞的情况

from gevent import monkey
monkey.patch_all()
功能 : 在导入socket模块之前使用,修改socket的IO设置行为

06_gevent_test.py

import gevent

def foo():
print(“Running in foo”)
gevent.sleep(2)
print(“switch to foo again”)

def bar():
print(“Running in bar”)
gevent.sleep(3)
print(“switch to bar again”)

#将两个函数设置为协成,此时协成函数运行
f = gevent.spawn(foo)
b = gevent.spawn(bar)

#回收协成
gevent.joinall([f,b])

Running in foo

Running in bar

switch to foo again

switch to bar again


#07_gevent_server.py

import gevent
from gevent import monkey
#需要在socket导入前执行,改变socket的属性
monkey.patch_all()
from socket import *

#套接字创建
def server(port):
s = socket()
s.bind((‘0.0.0.0’,port))
s.listen(5)
while True:
c,addr = s.accept()
print(‘Connect from’,addr)
gevent.spawn(handle,c)

#处理客户端请求
def handle©:
while True:
data = c.recv(1024).decode()
if not data:
break
print(“recv:”,data)
c.send(b"Receive your message")
c.close()

if name == “main”:
server(8888)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值