web服务器多任务并发
- 一、多进程版
- 二、多线程版
- 三、协程版
- 四、单线程-单进程-非堵塞-长连接
- 五、epoll版
- 六、总结
一、多进程版
import socket
import re
import multiprocessing
def service_client(new_socket):
data = new_socket.recv(1024).decode("utf-8")
data_list = data.splitlines()
ret = re.match(r"[^/]+(/[^ ]*)",data_list[0])
print(ret)
file_name = ""
if ret:
file_name = ret.group(1)
print(file_name)
if file_name == "/":
file_name = "/index.html"
try:
f = open("../static/html/Trave" + file_name, "rb")
except:
response = "HTTP/1.1 404 NOT FOUND\r\n"
response += "\r\n"
response += "Not Found"
new_socket.send(response.encode("utf-8"))
else:
response = "HTTP:/1.1 200 OK\r\n"
response += "\r\n"
data_contend = f.read()
f.close()
new_socket.send(response.encode("utf-8"))
new_socket.send(data_contend)
new_socket.close()
def main():
"""控制流程"""
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcp_server.bind(("", 8080))
tcp_server.listen(128)
while True:
new_client, addr = tcp_server.accept()
p = multiprocessing.Process(target=service_client, args=(new_client, ))
p.start()
new_client.close()
tcp_server.close()
if __name__ == "__main__":
main()
二、多线程版
import socket
import re
import threading
def service_client(new_socket):
data = new_socket.recv(1024).decode("utf-8")
data_list = data.splitlines()
ret = re.match(r"[^/]+(/[^ ]*)",data_list[0])
print(ret)
file_name = ""
if ret:
file_name = ret.group(1)
print(file_name)
if file_name == "/":
file_name = "/index.html"
try:
f = open("../static/html/Trave" + file_name, "rb")
except:
response = "HTTP/1.1 404 NOT FOUND\r\n"
response += "\r\n"
response += "Not Found"
new_socket.send(response.encode("utf-8"))
else:
response = "HTTP:/1.1 200 OK\r\n"
response += "\r\n"
data_contend = f.read()
f.close()
new_socket.send(response.encode("utf-8"))
new_socket.send(data_contend)
new_socket.close()
def main():
"""控制流程"""
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcp_server.bind(("", 8080))
tcp_server.listen(128)
while True:
new_client, addr = tcp_server.accept()
t = threading.Thread(target=service_client, args=(new_client, ))
t.start()
tcp_server.close()
if __name__ == "__main__":
main()
三、协程版
import socket
import re
import gevent
from gevent import monkey
monkey.patch_all()
def service_client(new_socket):
data = new_socket.recv(1024).decode("utf-8")
data_list = data.splitlines()
ret = re.match(r"[^/]+(/[^ ]*)",data_list[0])
print(ret)
file_name = ""
if ret:
file_name = ret.group(1)
print(file_name)
if file_name == "/":
file_name = "/index.html"
try:
f = open("../static/html/Trave" + file_name, "rb")
except:
response = "HTTP/1.1 404 NOT FOUND\r\n"
response += "\r\n"
response += "Not Found"
new_socket.send(response.encode("utf-8"))
else:
response = "HTTP:/1.1 200 OK\r\n"
response += "\r\n"
data_contend = f.read()
f.close()
new_socket.send(response.encode("utf-8"))
new_socket.send(data_contend)
new_socket.close()
def main():
"""控制流程"""
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcp_server.bind(("", 8080))
tcp_server.listen(128)
while True:
new_client, addr = tcp_server.accept()
gevent.spawn(service_client, new_client)
tcp_server.close()
if __name__ == "__main__":
main()
四、单线程-单进程-非堵塞-长连接
"""长连接 减少服务器资源的使用"""
import socket
import re
def service_client(new_socket, data):
data_list = data.splitlines()
ret = re.match(r"[^/]+(/[^ ]*)",data_list[0])
print(ret)
file_name = ""
if ret:
file_name = ret.group(1)
print(file_name)
if file_name == "/":
file_name = "/index.html"
try:
f = open("../static/html/Trave" + file_name, "rb")
except:
response_body = "Not Found".encode("utf-8")
response_header = "HTTP/1.1 404 NOT FOUND\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)
else:
data_contend = f.read()
f.close()
response_body = data_contend
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)
def main():
"""控制流程"""
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcp_server.bind(("", 8080))
tcp_server.listen(128)
tcp_server.setblocking(False)
new_client_list = list()
while True:
try:
new_client, addr = tcp_server.accept()
except Exception as ret:
pass
else:
new_client.setblocking(False)
new_client_list.append(new_client)
for client_socket in new_client_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_client_list.remove(client_socket)
tcp_server.close()
if __name__ == "__main__":
main()
五、epoll版
"""epoll 实现服务器最快的方法 linux下实现,windows下不能实现"""
import socket
import re
import select
def service_client(new_socket, data):
data_list = data.splitlines()
ret = re.match(r"[^/]+(/[^ ]*)",data_list[0])
print(ret)
file_name = ""
if ret:
file_name = ret.group(1)
print(file_name)
if file_name == "/":
file_name = "/index.html"
try:
f = open("../static/html/Trave" + file_name, "rb")
except:
response_body = "Not Found".encode("utf-8")
response_header = "HTTP/1.1 404 NOT FOUND\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)
else:
data_contend = f.read()
f.close()
response_body = data_contend
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)
def main():
"""控制流程"""
tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcp_server.bind(("", 8080))
tcp_server.listen(128)
epl = select.epoll()
epl.register(tcp_server.fileno(), select.EPOLLIN)
fd_event_dict = dict()
while True:
fd_event_list = epl.poll()
for fd, event in fd_event_list:
if fd == tcp_server.fileno():
new_client, addr = tcp_server.accept()
epl.register(new_client.fileno(), select.EPOLLIN)
fd_event_dict[new_client.fileno()] = new_client
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]
tcp_server.close()
if __name__ == "__main__":
main()
六、总结
- 多进程、多线程、协程,如果做个服务器什么最快???
epoll > 单进程、单线程、非堵塞 > 协程 > 多线程 > 多进程
- 单线程、单进程、非堵塞:的效率差在要以轮询的方式来检测是否收到数据,会复制一份套接字,也比较占内存
- epoll版快的原因:
利用的是事件通知的方式,而且是共享内存,所以比单线程、单进程、非堵塞的快
- epoll详解请点击这里