python前端开发服务器_Python 开发web服务器,多线程

https://blog.csdn.net/u012887259/article/details/102425450

https://blog.csdn.net/u012887259/article/details/102425450

https://www.jianshu.com/p/27a8cd3ec0f2

https://blog.csdn.net/u012887259/article/details/102425450

Python 开发web服务器,多线程

原创 海洋的渔夫

最后发布于2018-12-28 00:16:40

阅读数 16

收藏

发布于2018-12-28 00:16:40

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/u012887259/article/details/102425450

展开

仅供学习参考,转载请注明出处

前面介绍了使用进程的方式来优化处理http请求

Python 开发web服务器,多进程优化

但是多进程其实也存在一个资源的问题,当一个请求过来就要开启一个子进程的话,那么如果并发来了10万的http请求,那么就可能要开启10万个子进程。

这样是非常消耗服务器资源的。

那么另一个解决的方式就是使用线程。

改写线程的方式如下

运行效果如下:

https://blog.csdn.net/u012887259/article/details/102425450

Python 开发web服务器,多进程优化

仅供学习,转载请注明出处

前情回顾

但是这服务端是有一个致命的性能问题,那就是采用循环接收http请求。当在处理一个http请求的时候,需要等待这个请求处理完毕了,才会开始处理下一个http请求。

数量少的http请求当时还可以使用。

但是当并发http请求的数量巨大的时候,这样就会导致堵塞的情况,或者访问超时。

那么该怎么去优化这个问题呢?

查看上一篇章代码:使用html页面返回的web服务器

#coding=utf-8

from socket import *

import re

def handle_client(client_socket):

"""为一个客户端服务"""

# 接收对方发送的数据

recv_data = client_socket.recv(1024).decode("utf-8") # 1024表示本次接收的最大字节数

# 打印从客户端发送过来的数据内容

#print("client_recv:",recv_data)

request_header_lines = recv_data.splitlines()

for line in request_header_lines:

print(line)

# 返回浏览器数据

# 设置内容body

# 使用正则匹配出文件路径

print("------>",request_header_lines[0])

print("file_path---->","./html/" + re.match(r"[^/]+/([^\s]*)",request_header_lines[0]).group(1))

ret = re.match(r"[^/]+/([^\s]*)",request_header_lines[0])

if ret:

file_path = "./html/" + ret.group(1)

if file_path == "./html/":

file_path = "./html/index.html"

print("file_path *******",file_path)

try:

# 设置返回的头信息 header

response_headers = "HTTP/1.1 200 OK\r\n" # 200 表示找到这个资源

response_headers += "\r\n" # 空一行与body隔开

# 读取html文件内容

file_name = file_path # 设置读取的文件路径

f = open(file_name,"rb") # 以二进制读取文件内容

response_body = f.read()

f.close()

# 返回数据给浏览器

client_socket.send(response_headers.encode("utf-8")) #转码utf-8并send数据到浏览器

client_socket.send(response_body) #转码utf-8并send数据到浏览器

except:

# 如果没有找到文件,那么就打印404 not found

# 设置返回的头信息 header

response_headers = "HTTP/1.1 404 not found\r\n" # 200 表示找到这个资源

response_headers += "\r\n" # 空一行与body隔开

response_body = "

sorry,file not found

"

response = response_headers + response_body

client_socket.send(response.encode("utf-8"))

client_socket.close()

def main():

# 创建套接字

server_socket = socket(AF_INET, SOCK_STREAM)

# 设置当服务器先close 即服务器端4次挥手之后资源能够立即释放,这样就保证了,下次运行程序时 可以立即绑定7788端口

server_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)

# 设置服务端提供服务的端口号

server_socket.bind(('', 7788))

# 使用socket创建的套接字默认的属性是主动的,使用listen将其改为被动,用来监听连接

server_socket.listen(128) #最多可以监听128个连接

# 开启while循环处理访问过来的请求

while True:

# 如果有新的客户端来链接服务端,那么就产生一个新的套接字专门为这个客户端服务

# client_socket用来为这个客户端服务

# server_socket就可以省下来专门等待其他新的客户端连接while True:

client_socket, clientAddr = server_socket.accept()

handle_client(client_socket)

if __name__ == "__main__":

main()

12788725.html

从上面的文字解析可能不够形象,先使用代码实现一下。

将client_socket加入子进程中

12788725.html

import multiprocessing

# 设置子进程

new_process = multiprocessing.Process(target=handle_client,args=(client_socket,))

new_process.start() # 开启子进程

好了,这里就已经加好了子进程。那么下面来运行一下,看看会有什么结果。

12788725.html

从上面的访问请求中,一直在转圈,说明client_socket在处理完毕请求之后,并无法进行关闭。

其实,这个就是多进程的特性,子进程会从开启之前复制前面的代码,包含了client_socket接口,当子进程运行的时候,并无法关闭,这就需要从主进程来关闭了。

在主进程增加client_socket的关闭

12788725.html

运行看看浏览器还会不会转圈:

12788725.html

好了,那么到这里,就可以采用多进程的访问处理http请求了。

完整代码如下

#coding=utf-8

from socket import *

import re

import multiprocessing

def handle_client(client_socket):

"""为一个客户端服务"""

# 接收对方发送的数据

recv_data = client_socket.recv(1024).decode("utf-8") # 1024表示本次接收的最大字节数

# 打印从客户端发送过来的数据内容

#print("client_recv:",recv_data)

request_header_lines = recv_data.splitlines()

for line in request_header_lines:

print(line)

# 返回浏览器数据

# 设置内容body

# 使用正则匹配出文件路径

print("------>",request_header_lines[0])

print("file_path---->","./html/" + re.match(r"[^/]+/([^\s]*)",request_header_lines[0]).group(1))

ret = re.match(r"[^/]+/([^\s]*)",request_header_lines[0])

if ret:

file_path = "./html/" + ret.group(1)

if file_path == "./html/":

file_path = "./html/index.html"

print("file_path *******",file_path)

try:

# 设置返回的头信息 header

response_headers = "HTTP/1.1 200 OK\r\n" # 200 表示找到这个资源

response_headers += "\r\n" # 空一行与body隔开

# 读取html文件内容

file_name = file_path # 设置读取的文件路径

f = open(file_name,"rb") # 以二进制读取文件内容

response_body = f.read()

f.close()

# 返回数据给浏览器

client_socket.send(response_headers.encode("utf-8")) #转码utf-8并send数据到浏览器

client_socket.send(response_body) #转码utf-8并send数据到浏览器

except:

# 如果没有找到文件,那么就打印404 not found

# 设置返回的头信息 header

response_headers = "HTTP/1.1 404 not found\r\n" # 200 表示找到这个资源

response_headers += "\r\n" # 空一行与body隔开

response_body = "

sorry,file not found

"

response = response_headers + response_body

client_socket.send(response.encode("utf-8"))

#client_socket.close()

def main():

# 创建套接字

server_socket = socket(AF_INET, SOCK_STREAM)

# 设置当服务器先close 即服务器端4次挥手之后资源能够立即释放,这样就保证了,下次运行程序时 可以立即绑定7788端口

server_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)

# 设置服务端提供服务的端口号

server_socket.bind(('', 7788))

# 使用socket创建的套接字默认的属性是主动的,使用listen将其改为被动,用来监听连接

server_socket.listen(128) #最多可以监听128个连接

# 开启while循环处理访问过来的请求

while True:

# 如果有新的客户端来链接服务端,那么就产生一个新的套接字专门为这个客户端服务

# client_socket用来为这个客户端服务

# server_socket就可以省下来专门等待其他新的客户端连接while True:

client_socket, clientAddr = server_socket.accept()

# handle_client(client_socket)

# 设置子进程

new_process = multiprocessing.Process(target=handle_client,args=(client_socket,))

new_process.start() # 开启子进程

# 因为子进程已经复制了父进程的套接字等资源,所以父进程调用close不会将他们对应的这个链接关闭的

client_socket.close()

if __name__ == "__main__":

main()

12788725.html

关注微信公众号,回复【资料】、Python、PHP、JAVA、web,则可获得Python、PHP、JAVA、前端等视频资料。

一起写一个 Web 服务器(2) 一起写一个 Web 服务器(1) “发明创造时,我们学得最多” —— Piage...

绩重KF阅读 75评论 0赞 0

说明 本文 翻译自 realpython 网站上的文章教程 Socket Programming in Pytho...

keelii阅读 842评论 0赞 14

网络编程 一.楔子 你现在已经学会了写python代码,假如你写了两个python文件a.py和b.py,分别去运...

A_Python阅读 709评论 0赞 6

其实线程对于性能的提升在python中并不会很高,因为GIL这个全局锁的方式会对多线程进行锁定,导致性能损耗偏大。

关于GIL可参考该文章:Python 的 GIL 是什么鬼,多线程性能究竟如何

那么下一步,考虑可以使用协程gevent来优化。

完整代码

#coding=utf-8from socket import *import reimport threading def handle_client(client_socket): """为一个客户端服务""" # 接收对方发送的数据 recv_data = client_socket.recv(1024).decode("utf-8") # 1024表示本次接收的最大字节数 # 打印从客户端发送过来的数据内容 #print("client_recv:",recv_data) request_header_lines = recv_data.splitlines() for line in request_header_lines: print(line) # 返回浏览器数据 # 设置内容body # 使用正则匹配出文件路径 print("------>",request_header_lines[0]) print("file_path---->","./html/" + re.match(r"[^/]+/([^\s]*)",request_header_lines[0]).group(1)) ret = re.match(r"[^/]+/([^\s]*)",request_header_lines[0]) if ret: file_path = "./html/" + ret.group(1) if file_path == "./html/": file_path = "./html/index.html" print("file_path *******",file_path) try: # 设置返回的头信息 header response_headers = "HTTP/1.1 200 OK\r\n" # 200 表示找到这个资源 response_headers += "\r\n" # 空一行与body隔开 # 读取html文件内容 file_name = file_path # 设置读取的文件路径 f = open(file_name,"rb") # 以二进制读取文件内容 response_body = f.read() f.close() # 返回数据给浏览器 client_socket.send(response_headers.encode("utf-8")) #转码utf-8并send数据到浏览器 client_socket.send(response_body) #转码utf-8并send数据到浏览器 except: # 如果没有找到文件,那么就打印404 not found # 设置返回的头信息 header response_headers = "HTTP/1.1 404 not found\r\n" # 200 表示找到这个资源 response_headers += "\r\n" # 空一行与body隔开 response_body = "

sorry,file not found

" response = response_headers + response_body client_socket.send(response.encode("utf-8")) client_socket.close() def main(): # 创建套接字 server_socket = socket(AF_INET, SOCK_STREAM) # 设置当服务器先close 即服务器端4次挥手之后资源能够立即释放,这样就保证了,下次运行程序时 可以立即绑定7788端口 server_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 设置服务端提供服务的端口号 server_socket.bind(('', 7788)) # 使用socket创建的套接字默认的属性是主动的,使用listen将其改为被动,用来监听连接 server_socket.listen(128) #最多可以监听128个连接 # 开启while循环处理访问过来的请求 while True: # 如果有新的客户端来链接服务端,那么就产生一个新的套接字专门为这个客户端服务 # client_socket用来为这个客户端服务 # server_socket就可以省下来专门等待其他新的客户端连接while True: client_socket, clientAddr = server_socket.accept() # handle_client(client_socket) # 设置线程 new_thread = threading.Thread(target=handle_client,args=(client_socket,)) new_thread.start() # 开启线程 if __name__ == "__main__": main()

关注微信公众

————————————————

版权声明:本文为CSDN博主「海洋的渔夫」的原创文章,遵循CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/u012887259/java/article/details/102425450

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值