http协议、web服务器、并发服务器(上)
1. HTTP格式
每个HTTP请求和响应都遵循相同的格式,一个HTTP包含Header和Body两部分,其中Body是可选的。HTTP协议是一种文本协议,所以,它的格式也非常简单。
1.1 HTTP GET请求的格式:
GET /path HTTP/1.1
Header1: Value1
Header2: Value2
Header3: Value3
1.2 HTTP POST请求的格式:
POST /path HTTP/1.1
Header1: Value1
Header2: Value2
Header3: Value3
body data goes here...
当遇到连续两个\r\n时,Header部分结束,后面的数据全部是Body。
1.3 HTTP响应的格式:
HTTP/1.1 200 OK
Header1: Value1
Header2: Value2
Header3: Value3
body data goes here...
HTTP响应如果包含body,也是通过\r\n\r\n来分隔的。
请再次注意,Body的数据类型由Content-Type头来确定,如果是网页,Body就是文本,如果是图片,Body就是图片的二进制数据。
当存在Content-Encoding时,Body数据是被压缩的,最常见的压缩方式是gzip,所以,看到Content-Encoding: gzip时,需要将Body数据先解压缩,才能得到真正的数据。压缩的目的在于减少Body的大小,加快网络传输。
2. Web静态服务器-显示固定的页面
import socket
def handle_client(new_client):
"""处理客户端请求"""
recv_data = new_client.recv(1024)
print(recv_data)
# 组装响应的内容
response_headers = "HTTP/1.1 200 OK\r\n"
response_headers += "\r\n"
response_body = "6666"
response = response_headers + response_body
new_client.send(response.encode("utf-8"))
new_client.close()
def main():
# 创建套接字
tcp_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定本地消息
tcp_socket_server.bind(("", 8090))
# 套接字由主动变被动
tcp_socket_server.listen(128)
while True:
# 接收新的请求
new_client, client_addr = tcp_socket_server.accept()
handle_client(new_client)
# 关闭套接字
tcp_socket_server.close()
if __name__ == "__main__":
main()
如上的代码仅仅只是向浏览器发送了简单的文本内容:6666
在浏览器中访问:

3. Web静态服务器-显示需要的页面
import socket
import re
def handle_client(new_client):
"""处理客户端请求"""
recv_data = new_client.recv(1024).decode("utf-8")
# GET / HTTP/1.1
request_header_lines = recv_data.splitlines()
for line in request_header_lines:
print(line)
http_request_line = request_header_lines[0];
get_file_name = re.match("[^/]+(/[^ ]*)", http_request_line).group(1)
print("file name is -> " + get_file_name)
# print(recv_data)
if get_file_name == "/":
get_file_name = "/index.html"
root_path = "./html"
get_file_name = root_path + get_file_name;
try:
f = open(get_file_name, "rb")
except:
response_headers = "HTTP/1.1 404 NOT FOUND\r\n"
response_headers += "\r\n"
response_body = b"page not found"
else:
# 组装响应的内容
response_headers = "HTTP/1.1 200 OK\r\n"
response_headers += "\r\n"
response_body = f.read()
f.close()
new_client.send(response_headers.encode("utf-8"))
new_client.send(response_body)
new_client.close()
def main():
# 创建套接字
tcp_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_socket_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定本地消息
tcp_socket_server.bind(("", 8090))
# 套接字由主动变被动
tcp_socket_server.listen(128)
while True:
# 接收新的请求
new_client, client_addr = tcp_socket_server.accept()
handle_client(new_client)
# 关闭套接字
tcp_socket_server.close()
if __name__ == "__main__":
main()
在浏览器中访问:

4. Web静态服务器-多进程版
import socket
import re
import multiprocessing
def handle_client(new_client):
"""处理客户端请求"""
recv_data = new_client.recv(1024).decode("utf-8")
# GET / HTTP/1.1
request_header_lines = recv_data.splitlines()
for line in request_header_lines:
print(line)
http_request_line = request_header_lines[0];
get_file_name = re.match("[^/]+(/[^ ]*)", http_request_line).group(1)
print("file name is -> " + get_file_name)
# print(recv_data)
if get_file_name == "/":
get_file_name = "/index.html"
root_path = "./html"
get_file_name = root_path + get_file_name;
try:
f = open(get_file_name, "rb")
except:
response_headers = "HTTP/1.1 404 NOT FOUND\r\n"
response_headers += "\r\n"
response_body = b"page not found"
else:
# 组装响应的内容
response_headers = "HTTP/1.1 200 OK\r\n"
response_headers += "\r\n"
response_body = f.read()
f.close()
new_client.send(response_headers.encode("utf-8"))
new_client.send(response_body)
new_client.close()
def main():
# 创建套接字
tcp_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_socket_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定本地消息
tcp_socket_server.bind(("", 8090))
# 套接字由主动变被动
tcp_socket_server.listen(128)
while True:
# 接收新的请求
new_client, client_addr = tcp_socket_server.accept()
p = multiprocessing.Process(target=handle_client, args=(new_client,))
p.start()
new_client.close()
# 关闭套接字
tcp_socket_server.close()
if __name__ == "__main__":
main()
5. Web静态服务器-多线程版
import socket
import re
import threading
def handle_client(new_client):
"""处理客户端请求"""
recv_data = new_client.recv(1024).decode("utf-8")
# GET / HTTP/1.1
request_header_lines = recv_data.splitlines()
for line in request_header_lines:
print(line)
http_request_line = request_header_lines[0];
get_file_name = re.match("[^/]+(/[^ ]*)", http_request_line).group(1)
print("file name is -> " + get_file_name)
# print(recv_data)
if get_file_name == "/":
get_file_name = "/index.html"
root_path = "./html"
get_file_name = root_path + get_file_name;
try:
f = open(get_file_name, "rb")
except:
response_headers = "HTTP/1.1 404 NOT FOUND\r\n"
response_headers += "\r\n"
response_body = b"page not found"
else:
# 组装响应的内容
response_headers = "HTTP/1.1 200 OK\r\n"
response_headers += "\r\n"
response_body = f.read()
f.close()
new_client.send(response_headers.encode("utf-8"))
new_client.send(response_body)
new_client.close()
def main():
# 创建套接字
tcp_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_socket_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定本地消息
tcp_socket_server.bind(("", 8090))
# 套接字由主动变被动
tcp_socket_server.listen(128)
while True:
# 接收新的请求
new_client, client_addr = tcp_socket_server.accept()
t = threading.Thread(target=handle_client, args=(new_client,))
t.start()
# 关闭套接字
tcp_socket_server.close()
if __name__ == "__main__":
main()
6. Web静态服务器-gevent版
import socket
import re
import gevent
from gevent import monkey
monkey.patch_all()
def handle_client(new_client):
"""处理客户端请求"""
recv_data = new_client.recv(1024).decode("utf-8")
# GET / HTTP/1.1
request_header_lines = recv_data.splitlines()
for line in request_header_lines:
print(line)
http_request_line = request_header_lines[0];
get_file_name = re.match("[^/]+(/[^ ]*)", http_request_line).group(1)
print("file name is -> " + get_file_name)
# print(recv_data)
if get_file_name == "/":
get_file_name = "/index.html"
root_path = "./html"
get_file_name = root_path + get_file_name;
try:
f = open(get_file_name, "rb")
except:
response_headers = "HTTP/1.1 404 NOT FOUND\r\n"
response_headers += "\r\n"
response_body = b"page not found"
else:
# 组装响应的内容
response_headers = "HTTP/1.1 200 OK\r\n"
response_headers += "\r\n"
response_body = f.read()
f.close()
new_client.send(response_headers.encode("utf-8"))
new_client.send(response_body)
new_client.close()
def main():
# 创建套接字
tcp_socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_socket_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定本地消息
tcp_socket_server.bind(("", 8090))
# 套接字由主动变被动
tcp_socket_server.listen(128)
while True:
# 接收新的请求
new_client, client_addr = tcp_socket_server.accept()
g = gevent.spawn(handle_client, new_client)
g.join()
# 关闭套接字
tcp_socket_server.close()
if __name__ == "__main__":
main()
http协议、web服务器、并发服务器(上)的更多相关文章
- web服务器-并发服务器2
阅读目录 1.Web静态服务器-5-非堵塞模式 2.Web静态服务器-6-epoll 3.Web静态服务器-7-gevent版 4.知识扩展-C10K问题 一.Web静态服务器-5-非堵塞模式 单进程 ...
- 14_Web服务器-并发服务器
1.服务器概述 1.硬件服务器(IBM,HP): 主机 集群 2.软件服务器(HTTPserver Django flask): 网络服务器,在后端提供网络功能逻辑处理数据处理的程序或者架构等 3.服 ...
- Python复习笔记(十)Http协议--Web服务器-并发服务器
1. HTTP协议(超文本传输协议) 浏览器===>服务器发送的请求格式如下:(浏览器告诉服务器,浏览器的信息) GET / HTTP/1.1 Host: www.baidu.com Conne ...
- Web服务器-并发服务器-Epoll(3.4.5)
@ 目录 1.介绍 2.代码 关于作者 1.介绍 epoll是一种解决方案,nginx就是用的这个 中心思想:不要再使用多进程,多线程了,使用单进程,单线程去实现并发 在上面博客实现的代码中使用过的轮 ...
- Web服务器-并发服务器-单进程单线程非堵塞方式(3.4.3)
@ 目录 1.分析 2.代码 关于作者 1.分析 当socket去监听的时候,是堵塞的状态 通过tcp_sever_socket.setblocking(False)去设置不堵塞 当socket发现没 ...
- Web服务器-并发服务器-长连接(3.4.4)
@ 目录 1.说明 2.代码 关于作者 1.说明 每次new_socket都被强制关闭,造成短连接 所提不要关闭套接字 但是不关闭的话,浏览器不知道发完没有啊 此时用到header的属性Content ...
- Web服务器-并发服务器-协程 (3.4.2)
@ 目录 1.分析 2.代码 关于作者 1.分析 随着网站的用户量越来愈多,通过多进程多线程的会力不从心 使用协程可以缓解这一问题 只要使用gevent实现 2.代码 from socket impo ...
- Web服务器-并发服务器-多进程(3.4.1)
@ 目录 1.优化分析 2.代码 3. 关于作者 1.优化分析 在单进程的时候,相当于 是来一个客户,派一个人去服务一下 效率低,现在使用多进程来服务 假设场景 100个人同时访问页面 单进程:一次处 ...
- linux学习之多高并发服务器篇(一)
高并发服务器 高并发服务器 并发服务器开发 1.多进程并发服务器 使用多进程并发服务器时要考虑以下几点: 父最大文件描述个数(父进程中需要close关闭accept返回的新文件描述符) 系统内创建进程 ...
- 手把手让你实现开源企业级web高并发解决方案(lvs+heartbeat+varnish+nginx+eAccelerator+memcached)
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://freeze.blog.51cto.com/1846439/677348 此文凝聚 ...
随机推荐
- [转载]你所不了解的DevOps
DevOps开发运维训练营 一旦建立了创新的文化,即使那些并非科学家或者工程师的人——诗人.演员.记者——也能以团体的形式,接受科学文化的意义.他们信奉创新文化的概念.他们以促进这种文化的方式投票.他 ...
- [转]语言模型训练工具SRILM
SRILM是一个建立和使用统计语言模型的开源工具包,从1995年开始由SRI 口语技术与研究实验室(SRI Speech Technology and Research Laboratory)开发,现 ...
- 应用监控CAT之cat-consumer源码阅读(二)
之前讲了 cat-client 进行cat埋点上报,那么上报给谁呢?以及后续故事如何?让我们来看看 cat-consumer 是如何接收处理的? 由cat-client发送数据,cat-consume ...
- Linux rpm包安装不了
有时候会发现安装rpm包时会报错,解决办法: 到rpm包所在目录执行 createrepo -v ./ 这个命令 然后会生成一个repodate这个目录,然后在进行安装rpm就可以了!
- Java对象的克隆和深浅问题
Java实现克隆的方式 Java实现克隆的方式有如下两种, 推荐采用实现Cloneable接口的方式 实现Cloneable接口, 重写clone方法, 调用父类的clone方法 还有另一种方法, 不 ...
- insert update delete 语法 以及用法
insert update delete 被称为 数据定义语句语句 也就是数据的增加 修改 删除 其中不包括查询 譬如: create database -创建数据库 alter database - ...
- Redis 再牛逼,也得设置密码!!
Redis 你再牛逼也得设置密码啊,不然会有安全漏洞,造成一些隐患. 还有,比如像出现下面这样的错,需要设置密码,或者关闭保护模式,所以还是设置密码比较安全.不然只能本地操作,不能远程连接. DENI ...
- Mac 下使用svn
作为一个一直使用windows系统的人,还真不知道mac上的svn如何使用,偶然机会下现在需要. 查过后发现 mac 是自带svn的,在我装好xcode后,再安装 Command Line Tools ...
- .Net 并发写入文件的多种方式
1.简介 本文主要演示日常开发中利用多线程写入文件存在的问题,以及解决方案,本文使用最常用的日志案例! 2.使用File.AppendAllText写入日志 这是种常规的做法,通过File定位到日志文 ...
- TypeError: Cannot red property 'style' of null 错误解决
错误信息如下: JSP代码如下: <c:if test ="${not empty excelErrors}"> <div id="excelError ...