通过【多线程】【多进程】【协程】实现多任务HTTP服务器,以及通过 单任务 实现非堵塞(并发)

【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()

实现流程概述:

  1. 先实现单任务 HTTP 服务器的简单功能
  2. 导入 multiprocessing模块
  3. 在 主函数中调用 multiprocessing中的Process创建 实例对象
  4. 实例调用 start 函数,完成多任务的实现

【2】通过多线程实现多任务HTTP服务器

最终效果:在这里插入图片描述

实现流程概述:

  1. 先实现单任务的 HTTP 服务器
  2. 导入 threading模块
  3. 在主函数中 调用 threding中的Thread创建实例 p2
  4. 调用 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()

实现流程概述:

  1. 实现简单的单任务HTTP服务器
  2. 导入 gevent模块
  3. 导入 gevent模块中的monkye函数
  4. 调用 patch_all,意思是,整个代码中,凡是关于 延时的函数,全都自动换成gevent里面的函数(协程就是 利用函数延时这段时间去完成其他的事)
  5. 主函数中调用 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()

实现流程概述:

  1. 实现简单单任务 HTTP服务器
  2. tcp_sockettcp_socket.setblocking(False)实现非堵塞
  3. 进行思路构建——首先,这里tcp_socket已经实现非堵塞,在没有客户端连接的情况下会在 accept 这里发生报错,所以这里需要一个异常判断。
  4. 其次,因为这里我们需要的是,用单任务实现多任务的功能,不得不避免 new_socket 在连接之后被丢弃的问题,这里需要建立一个 列表,用来存放 new_socket
  5. 下面,调用 函数server_c,在这里,起初需要把new_socket 放进列表中,然后把new_socket设置成 非堵塞,我们又面临下一个问题,这里客户端不发数据的时候,一定会报错,所以这里也需要一个异常判断。
  6. 接下来,就是 从list_newsock中取值,进行循环处理,这里有个问题,就是当客户端关闭之后,列表中仍然存在 new_socket的值,这就导致,连接的客户端越多,服务器越卡,所以这里,需要进行处理——list_newsock.remove(),当确定客户端已经关闭的时候,可以把 关闭客户端的 new——socket移除列表。
  7. 最后 用NetAssist进行实验
发布了36 篇原创文章 · 获赞 75 · 访问量 5467

猜你喜欢

转载自blog.csdn.net/weixin_44449518/article/details/96885347
今日推荐