Python日常笔记(29)- 模仿web服务器-非阻塞版本

模仿web服务器 - 多进程-多线程-协程实现-短连接非阻塞

# 导入socket
import socket
# 导入多线程
import threading
# 导入进程
import multiprocessing
# 导入协程工具包
import gevent
from gevent import monkey
# 导入正则表达式
import re

# 将程序中用到的耗时操作的代码,换为gevent中自己实现的模块,必须执行的方法
monkey.patch_all()


def send_error(tcp_clinet_socket):
   # 否则返回一个没有找到页面
   response = "HTTP/1.1 404 NOT FOUND\r\n"
   response += "\r\n"
   response += "没有找到该页面"
   tcp_clinet_socket.send(response.encode("gbk")) # 先发送头部


def getClientMsg(tcp_clinet):
   # 获取客户端数据
   msg_data = tcp_clinet.recv(1024).decode("utf-8")
   # 解析数据GET /index.html HTTP/1.1
   msg_list = msg_data.splitlines() # 将数据切割成序列
   ret = re.match(r"[^/]+ (/[^ ]*)", msg_list[0])
   file_name = None
   if ret:
       file_name = ret.group(1)
       if file_name == "/":
           file_name = "/index.html"

       local_file_name = "." + file_name

       response = "HTTP/1.1 200 OK\r\n"
       response += "\r\n"
       try:
           f = open(local_file_name, "rb")
       except:
           send_error(tcp_clinet) # 没有找到页面发送次数据
       else:
           # 发送数据到客户端
           tcp_clinet.send(response.encode("utf-8"))
           tcp_clinet.send(f.read())
           f.close()
   else:
       send_error(tcp_clinet) # 没有找到页面发送次数据
   # 关闭客户端链接
   tcp_clinet.close()


def main():
   # 创建套接字
   tcp_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   # 绑定ip和端口
   tcp_socket_server.bind(("", 9999))
   # 启动监听
   tcp_socket_server.listen(128)
   while True:
       # 等待客户端链接
       tcp_clinet, addr_clinet = tcp_socket_server.accept()
       # 获取客户端信息,并返回信息
       """
        # 单任务执行
        getClientMsg(tcp_clinet)
       """
       """
       # 使用多线程执行
       p = threading.Thread(target=getClientMsg, args=(tcp_clinet,))
       # 启动线程
       p.start()
       """
       """
           # 多进程使用执行
           m = multiprocessing.Process(target=getClientMsg, args=(tcp_clinet,))
           # 启动进程 m.start()
           # 由于多任务是所有的执行代码都拷贝,所以这里也需要关闭一次
           #tcp_clinet.close()
       """
       # 使用协程执行,必须在要执行的协程代码头部运行monkey.patch_all()方法
       gevent.spawn(getClientMsg, tcp_clinet)

if __name__ == "__main__":
   main()

然后在浏览器访问127.0.0.1/index.html页面就可以访问了,前提是你本地有一个index.html页面

使用非阻塞长连接的模式来书写案例

# 导入socket
import socket
# 导入正则表达式
import re
import time


def send_error(tcp_clinet_socket):
   # 否则返回一个没有找到页面
   response = "HTTP/1.1 404 NOT FOUND\r\n"
   response += "\r\n"
   response += "没有找到该页面"
   tcp_clinet_socket.send(response.encode("gbk")) # 先发送头部
   # 在异常中需要关闭一下套接字,否则客户端不停的等待访问
   tcp_clinet_socket.close()


def getClientMsg(tcp_clinet, msg_data):
   # 解析数据GET /index.html HTTP/1.1
   msg_list = msg_data.splitlines() # 将数据切割成序列
   ret = re.match(r"[^/]+ (/[^ ]*)", msg_list[0])
   file_name = None
   if ret:
       file_name = ret.group(1)
       if file_name == "/":
           file_name = "/index.html"

       local_file_name = "." + file_name

       try:
           f = open(local_file_name, "rb")
       except:
           send_error(tcp_clinet) # 没有找到页面发送次数据
       else:
           # 发送数据到客户端
           response_body = f.read()
           response_header = "HTTP/1.1 200 OK\r\n"
           # 加了这个头信息,是返回body长度,就不需要在关闭socket.close方法,客户端就知道了
           response_header += "Content-Length:%d\r\n" % len(response_body)
           response_header += "\r\n"

           response = response_header.encode("utf-8") + response_body
           print(response)
           tcp_clinet.send(response)
           f.close()
   else:
       send_error(tcp_clinet) # 没有找到页面发送次数据


def main():
   # 创建套接字
   tcp_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
   # 绑定ip和端口
   tcp_socket_server.bind(("", 9999))
   # 启动监听
   tcp_socket_server.listen(128)
   # 将套接字改为非阻塞
   tcp_socket_server.setblocking(False)

   # 定义一个序列储存客户端链接
   client_socket_list = list()
   while True:
       time.sleep(1)
       # 等待客户端链接,这里由于获取不到链接所以需要使用异常处理
       try:
           tcp_clinet, addr_clinet = tcp_socket_server.accept()
       except:
           print("没有链接=======")
       else:
           # 获取客户端信息,并返回信息
           client_socket_list.append(tcp_clinet)
           # 如果有客户端链接,将客户端套接字也设置为非阻塞
           tcp_clinet.setblocking(False)

       # 循环所有客户端套接字来接收数据
       for client in client_socket_list:
           try:
               data = client.recv(1024).decode("utf-8")
           except:
               print("没有接收到数据======")
           else:
               if data:
                   getClientMsg(client, data)
               else:
                   # 关闭客户端套接字资源
                   client.close()
                   # 删除套接字
                   client_socket_list.remove(client)


if __name__ == "__main__":
   main()

作者:阿超
原创公众号:『Python日常笔记』,专注于 Python爬虫等技术栈和有益的程序人生,会将一些平时的日常笔记都慢慢整理起来,也期待你的关注和阿超一起学习,公众号回复【csdn】优质资源。

发布了55 篇原创文章 · 获赞 16 · 访问量 9510

猜你喜欢

转载自blog.csdn.net/duchaochen/article/details/105069532
今日推荐