做web开发的你,真的熟悉web服务器处理机制吗?

分析请求数据

下面是一段原始的请求数据:

b'GET / HTTP/1.1\r\nHost: 127.0.0.1:8000\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.8\r\nCookie: csrftoken=gnaOXtlMlCxgjq62jUzBjv6XedPpVvxotWq2R6KpTv9dK2eHCwXlApyNEl9anzp9\r\n\r\n'

是不是有种似曾相识的感觉,没错,打开chrome开发者工具,随便打开一个网页,就可以看到如上信息,只不过发送到服务器端就是上面的格式,已\r\n分割处理。

  • 通过分析以上内容,可以发现各项之间都是以\r\n分割
  • 最后以2个\r\n结束,也就是我们在响应给客户端时,内容和响应头中间就是用2个\r\n分割

简单的webserver实现

1、静态资源

主要思路如下:

  1. 开启socket服务监听客户端连接
  2. 采用多进程方式实现并发连接处理
  3. 基于报文分析规则,拼接响应内容,输出到客户端

代码如下:

`
# coding:utf-8

import socket
import re from multiprocessing import Process HTML_ROOT_DIR = './static' class WebServer(object):
'''
简单的webserver
''' def __init__(self):
self.sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) def start(self):
self.sock_server.listen(128)
while True:
sock_client, addr = self.sock_server.accept()
print('[%s,%s]用户已连接......' % addr)
handle_client_process = Process(target=self.handle_client, args=(sock_client,))
handle_client_process.start()
sock_client.close() def handle_client(self, sock_client):
'''处理客户端请求'''
recv_data = sock_client.recv(1024)
#print('请求数据:', recv_data)
req_lines = recv_data.splitlines()
#for line in req_lines:
# print(line) req_start_line = req_lines[0]
#print(req_start_line.decode('utf-8'))
file_name = re.match(r'\w+ +(/[^ ]*) ', req_start_line.decode('utf-8')).group(1)
if '/' == file_name:
file_name = "/index.html" try:
file = open(HTML_ROOT_DIR + file_name, 'rb')
except IOError:
resp_start_line = 'HTTP/1.1 404 Not Found\r\n'
resp_headers = 'Server: My Web Server\r\n'
resp_body = 'The file is not found!'
else:
file_data = file.read()
file.close() resp_start_line = 'HTTP/1.1 200 OK\r\n'
resp_headers = 'Server: My Web Server\r\n'
resp_body = file_data.decode('utf-8') # 构造响应内容
resp_data = resp_start_line + resp_headers + '\r\n' + resp_body
#print('构造响应内容:', resp_data) # response
sock_client.send(bytes(resp_data, 'utf-8')) # 关闭客户端连接
sock_client.close() def bind(self, port):
self.sock_server.bind(('', port)) def main():
webServer = WebServer()
webServer.bind(8000)
webServer.start() if __name__ == '__main__':
main()
` 
  • 地址栏输入:127.0.0.1:8000

2、动态资源

主要思路如下:

  1. 开启socket服务监听客户端连接
  2. 采用多进程方式实现并发连接处理
  3. 基于报文分析规则,如果是以.py结尾的请求,自动分发到相应的模块做处理

web服务器,代码如下:

`
# coding:utf-8

import socket
import re
import sys from multiprocessing import Process HTML_ROOT_DIR = './static'
WSGI_PY = './wsgipy' class WebServer(object):
'''
简单的webserver
''' def __init__(self):
self.sock_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) def start(self):
self.sock_server.listen(128)
while True:
sock_client, addr = self.sock_server.accept()
print('[%s,%s]用户已连接......' % addr)
handle_client_process = Process(target=self.handle_client, args=(sock_client,))
handle_client_process.start()
sock_client.close() def start_response(self, status, headers):
"""
status = "200 OK"
headers = [
("Content-Type", "text/plain")
]
star
"""
resp_headers = 'HTTP/1.1 ' + status + '\r\n'
for header in headers:
resp_headers += '%s: %s\r\n' % header self.resp_headers = resp_headers def handle_client(self, sock_client):
'''处理客户端请求'''
recv_data = sock_client.recv(1024)
#print('请求数据:', recv_data)
req_lines = recv_data.splitlines()
#for line in req_lines:
# print(line) req_start_line = req_lines[0]
#print(req_start_line.decode('utf-8'))
file_name = re.match(r'\w+ +(/[^ ]*) ', req_start_line.decode('utf-8')).group(1)
method = re.match(r'(\w+) +/[^ ]*',req_start_line.decode("utf-8")).group(1) if file_name.endswith('.py'):
try:
m = __import__(file_name[1:-3])
except Exception:
self.resp_headers = 'HTTP/1.1 404 Not Found\r\n'
resp_body = 'not found'
else:
env = {
'PATH_INFO': file_name,
'METHOD': method
}
resp_body = m.application(env, self.start_response)
resp_data = self.resp_headers+'\r\n'+resp_body
else:
if '/' == file_name:
file_name = '/index.html' try:
file = open(HTML_ROOT_DIR + file_name, 'rb')
except IOError:
resp_start_line = 'HTTP/1.1 404 Not Found\r\n'
resp_headers = 'Server: My Web Server\r\n'
resp_body = 'The file is not found!'
else:
file_data = file.read()
file.close() resp_start_line = 'HTTP/1.1 200 OK\r\n'
resp_headers = 'Server: My Web Server\r\n'
resp_body = file_data.decode('utf-8') # 构造响应内容
resp_data = resp_start_line + resp_headers + '\r\n' + resp_body
#print('构造响应内容:', resp_data) # response
sock_client.send(bytes(resp_data, 'utf-8')) # 关闭客户端连接
sock_client.close() def bind(self, port):
self.sock_server.bind(('', port)) def main():
sys.path.insert(1,WSGI_PY)
webServer = WebServer()
webServer.bind(8000)
webServer.start() if __name__ == '__main__':
main() ` helloworld.py:
`
# coding:Utf-8

def application(env,start_response):
status = '200 OK'
headers = [
('Content-Type','text/plain')
]
start_response(status,headers)
return 'hello world'
`  

主要是技术点解析:

  1、根据请求 .py 名称自动导入模块,使用了一个小魔法:m = __import__('filename') ,会返回具体应用,然后根据应用实例调用具体处理程序。

  2、在具体的应用中设置状态码、响应头;application(env,start_response)其中env是request信息,start_response是web服务器中的函数,通过调用start_response(status,headers)把状态码和headers传递给web服务器,这样web服务器就可以拿到status、headers拼接response

  3、具体应用中返回响应体response_body,也就是应用中的return 'hello world',结合2中的status、headers得到最终的response data发给客户端

代码已上传到github:python 小程序

基于python实现简单web服务器的更多相关文章

  1. python 启动简单web服务器

    有时我们在开发web静态页面时,需要一个web服务器来测试. 这时可以利用python提供的web服务器来实现. 1.在命令行下进入某个目录 2.在该目录下运行命令: python -m Simple ...

  2. Python实现简单Web服务器

    实验楼教程链接: https://www.shiyanlou.com/courses/552/labs/1867/document http原理详解(http下午茶): https://www.kan ...

  3. Websocket - Websocket原理(握手、解密、加密)、基于Python实现简单示例

    一.Websocket原理(握手.解密.加密) WebSocket协议是基于TCP的一种新的协议.WebSocket最初在HTML5规范中被引用为TCP连接,作为基于TCP的套接字API的占位符.它实 ...

  4. C#中使用Socket实现简单Web服务器

    上一篇博客中介绍了怎样使用socket访问web服务器.关键有两个: 熟悉Socket编程: 熟悉HTTP协议. 上一篇主要是通过socket来模拟浏览器向(任何)Web服务器发送(HTTP)请求,重 ...

  5. tomcat解析之简单web服务器(图)

    链接地址:http://gogole.iteye.com/blog/587163 之前有javaeyer推荐了一本书<how tomcat works>,今天晚上看了看,确实不错,第一眼就 ...

  6. Socket网络编程--简单Web服务器(1)

    这一次的Socket系列准备讲Web服务器.就是编写一个简单的Web服务器,具体怎么做呢?我也不是很清楚流程,所以我找来了一个开源的小的Web服务器--tinyhttpd.这个服务器才500多行的代码 ...

  7. Socket网络编程--简单Web服务器(6)

    本来是想实现ssl连接的,但是弄了好久都不成功,就索性不做了,等以后有能力再做了.所以这一小节就是本次的最后一节了.就简单的说几个注意点. 1.加个配置文件 使用单例模式,使用一个类,该类保存一些信息 ...

  8. Python实现简单HTTP服务器

    Python实现简单HTTP服务器(一) 一.返回固定内容 复制代码 coding:utf-8 import socket from multiprocessing import Process de ...

  9. Java 18 新特性:简单Web服务器 jwebserver

    在今年3月下旬的时候,Java版本已经更新到了18.接下来DD计划持续做一个系列,主要更新从Java 9开始的各种更新内容,但我不全部都介绍,主要挑一些有意思的内容,以文章和视频的方式来给大家介绍和学 ...

随机推荐

  1. 新人补钙系列教程之:Molehill底层API中最重要的Context3D

    Context3D,是一个三维空间的处理环境,负责创建并处理三维对象的各个要素如顶点.片段.透视等等,并将处理的结果使用AGAL(Adobe图形汇编语言)上传给显卡进行运算,运算结果最终被回传给CPU ...

  2. 面试——谈谈对JAVA的理解

    谈谈你对Java平台的理解.答:Java首先是一种面向对象的语言,语言特性有封装,继承,多态,泛型,Lamda表达式等; 第二个特性:支持跨平台,一次书写导出运行(write once,run any ...

  3. CountDownLatch模拟高并发测试代码

    直接上代码进行验证吧 /** * 通过countdownlatch的机制,来实现并发运行 * 模拟200个并发测试 * @author ll * @date 2018年4月18日 下午3:55:59 ...

  4. golang sync.Cond 类

    众所周知,go语言在多线程方面的支持是十分完备的.在go语言sync包中提供了一个Cond类,这个类用于goroutine之间进行协作. 这个类并不复杂,只有三个函数,Broadcast() , Si ...

  5. 自己写的粗糙的Excel数据驱动Http接口测试框架(一)

    1.excel用例: 2.用例执行: @Testpublic void BindBank() throws Exception { String fileName = "src/main/j ...

  6. Nodejs 模拟telnet

    代码下载:https://files.cnblogs.com/files/xiandedanteng/nodejsTelnet.rar 效果: server.js代码: var net=require ...

  7. 【Android工具类】怎样保证Android与server的DES加密保持一致

    转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 在我们的应用程序涉及到比較敏感的数据的时候,我们一般会对数据进行简单的加密.在与server之间的数据交互中 ...

  8. PS 如何制作环绕文字效果

    最终效果 地球素材 1.打开素材,使用椭圆选区工具按住shift绘制正圆选区 2.转到路径面板,将选区变为工作路径 3.选择文字工具,在路径上输入文字 4.ctrl+T,按住ctrl+alt,鼠标拖动 ...

  9. 百度兴趣点下载V1.4版

    好东西就是不断的更改,升级出来的,经过连续四个版本的升级,本次版本受到用户的一致好评,也拿来在这里做个分享,期望对更多地用户起到一定的帮助! 还是一样,介绍一下其功能: 1.全国范围内的兴趣点任意区域 ...

  10. Python3链接MySQL数据库

    Python 2.x 上连接MySQL的库倒是不少的,其中比较著名就是MySQLdb(Django项目都使用它:我也在开发测试系统时也使用过),见:http://sourceforge.net/pro ...