【1】通过多进程实现多任务HTTP服务器
这是完成后的效果:
多任务可以达到的效果,不同的客户端,可以在同一时刻访问服务器:
下面是 实现功能的代码:
import socket
import re
import multiprocessing
def server_c(new_socket):
# 接受客户端发来的消息
request = new_socket.recv(1024).decode("utf-8")
if request:
# 把客户端请求的信息 提取出有用的请求页面信息
line = request.splitlines()
result = re.match(r"[^/]+(/[^ ]*)", line[0])
# 提取需要的页面信息
try:
html_msg = result.group(1)
# 打开请求的页面,读取网页源码,发送给浏览器
f = open("." + html_msg, "rb")
content = f.read()
# 发送回应的头部信息
response = "HTTP/1.1 200 OK\r\n"
response += "\r\n"
new_socket.send(response.encode("utf-8"))
# 发送请求的页面主体信息
new_socket.send(content)
new_socket.close()
print("-------为客户端服务完成-----------")
except:
response = "HTTP/1.1 404 Error\r\n"
response += "\r\n"
response += "---------------Error----------404---------"
new_socket.send(response.encode("utf-8"))
new_socket.close()
else:
print("-----------客户端已关闭---------")
new_socket.close()
def main():
# 创建一个套接字
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定ip 和port
tcp_socket.bind(("", 7890))
# 设置侦听套接字
tcp_socket.listen(128)
while True:
# 等待客户端的连接
new_socket, user_addr = tcp_socket.accept()
# 连接客户端,为客户端服务
p = multiprocessing.Process(target=server_c, args=(new_socket,))
p.start()
new_socket.close()
# server_c(new_socket)
tcp_socket.close()
if __name__ == '__main__':
main()
实现流程概述:
- 先实现单任务 HTTP 服务器的简单功能
- 导入
multiprocessing
模块 - 在 主函数中调用
multiprocessing
中的Process
创建 实例对象 - 实例调用
start
函数,完成多任务的实现
【2】通过多线程实现多任务HTTP服务器
最终效果:
实现流程概述:
- 先实现单任务的 HTTP 服务器
- 导入
threading
模块 - 在主函数中 调用
threding
中的Thread
创建实例 p2 - 调用
start
函数实现多线程多任务
【3】利用协程实现多任务HTTP服务器
实现效果:
具体代码:
import socket
import re
import gevent
from gevent import monkey
monkey.patch_all()
def server_c(new_socket):
# 接受客户端发来的消息
request = new_socket.recv(1024).decode("utf-8")
if request:
# 把客户端请求的信息 提取出有用的请求页面信息
line = request.splitlines()
result = re.match(r"[^/]+(/[^ ]*)", line[0])
# 提取需要的页面信息
try:
html_msg = result.group(1)
# 打开请求的页面,读取网页源码,发送给浏览器
f = open("." + html_msg, "rb")
content = f.read()
# 发送回应的头部信息
response = "HTTP/1.1 200 OK\r\n"
response += "\r\n"
new_socket.send(response.encode("utf-8"))
# 发送请求的页面主体信息
new_socket.send(content)
new_socket.close()
print("-------为客户端服务完成-----------")
except:
response = "HTTP/1.1 404 Error\r\n"
response += "\r\n"
response += "---------------Error----------404---------"
new_socket.send(response.encode("utf-8"))
new_socket.close()
else:
print("-----------客户端已关闭---------")
new_socket.close()
def main():
# 创建一个套接字
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定ip 和port
tcp_socket.bind(("", 7890))
# 设置侦听套接字
tcp_socket.listen(128)
while True:
# 等待客户端的连接
new_socket, user_addr = tcp_socket.accept()
# 连接客户端,为客户端服务
gevent.spawn(server_c, new_socket)
# new_socket.close()
# server_c(new_socket)
tcp_socket.close()
if __name__ == '__main__':
main()
实现流程概述:
- 实现简单的单任务HTTP服务器
- 导入
gevent
模块 - 导入
gevent
模块中的monkye
函数 - 调用
patch_all
,意思是,整个代码中,凡是关于 延时的函数,全都自动换成gevent
里面的函数(协程就是 利用函数延时这段时间去完成其他的事) - 主函数中调用
gevent.spawn()
函数,完成协程多任务(并发)的实现
【4】单任务HTTP服务器实现 非堵塞(并发)
实现效果:
具体实现代码:
import socket
import re
import time
def server_c(new_socket, list_newsock):
new_socket.setblocking(False)
# 接受客户端发来的消息
try:
list_newsock.append(new_socket)
request = new_socket.recv(1024).decode("utf-8")
except:
print("---------未收到客户端的消息-----------")
else:
for client_servre in list_newsock:
if request:
# 把客户端请求的信息 提取出有用的请求页面信息
line = request.splitlines()
result = re.match(r"[^/]+(/[^ ]*)", line[0])
# 提取需要的页面信息
try:
html_msg = result.group(1)
# 打开请求的页面,读取网页源码,发送给浏览器
f = open("." + html_msg, "rb")
content = f.read()
# 发送回应的头部信息
response = "HTTP/1.1 200 OK\r\n"
response += "\r\n"
client_servre.send(response.encode("utf-8"))
# 发送请求的页面主体信息
client_servre.send(content)
client_servre.close()
print("-------为客户端服务完成-----------")
except:
response = "HTTP/1.1 404 Error\r\n"
response += "\r\n"
response += "---------------Error----------404---------"
client_servre.send(response.encode("utf-8"))
client_servre.close()
else:
print("-----------客户端已关闭---------")
list_newsock.remove(client_servre)
client_servre.close()
def main():
# 创建一个套接字
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定ip 和port
tcp_socket.bind(("", 7890))
# 设置侦听套接字
tcp_socket.listen(128)
tcp_socket.setblocking(False)
list_newsock = list()
while True:
# 等待客户端的连接
try:
new_socket, user_addr = tcp_socket.accept()
except:
print("----------没有客户端连接----------")
time.sleep(0.5)
# 连接客户端,为客户端服务
else:
server_c(new_socket, list_newsock)
#gevent.spawn(server_c, new_socket)
# new_socket.close()
# server_c(new_socket)
tcp_socket.close()
if __name__ == '__main__':
main()
实现流程概述:
- 实现简单单任务 HTTP服务器
- 把
tcp_socket
用tcp_socket.setblocking(False)
实现非堵塞 - 进行思路构建——首先,这里
tcp_socket
已经实现非堵塞,在没有客户端连接的情况下会在 accept 这里发生报错,所以这里需要一个异常判断。 - 其次,因为这里我们需要的是,用单任务实现多任务的功能,不得不避免
new_socket
在连接之后被丢弃的问题,这里需要建立一个 列表,用来存放new_socket
- 下面,调用 函数
server_c
,在这里,起初需要把new_socket
放进列表中,然后把new_socket
设置成 非堵塞,我们又面临下一个问题,这里客户端不发数据的时候,一定会报错,所以这里也需要一个异常判断。 - 接下来,就是 从
list_newsock
中取值,进行循环处理,这里有个问题,就是当客户端关闭之后,列表中仍然存在new_socket
的值,这就导致,连接的客户端越多,服务器越卡,所以这里,需要进行处理——list_newsock.remove()
,当确定客户端已经关闭的时候,可以把 关闭客户端的new——socket
移除列表。 - 最后 用
NetAssist
进行实验