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...

当遇到连续两个 时,Header部分结束,后面的数据全部是Body。

1.3 HTTP响应的格式:

HTTP/1.1 200 OK
Header1: Value1
Header2: Value2
Header3: Value3

body data goes here...

HTTP响应如果包含body,也是通过 来分隔的。

请再次注意,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
"
        response_headers += "
"
        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
"
		response_headers += "
"
		response_body = b"page not found"
	else:	
	
		# 组装响应的内容
		response_headers = "HTTP/1.1 200 OK
"
		response_headers += "
"
		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
"
		response_headers += "
"
		response_body = b"page not found"
	else:	
	
		# 组装响应的内容
		response_headers = "HTTP/1.1 200 OK
"
		response_headers += "
"
		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
"
		response_headers += "
"
		response_body = b"page not found"
	else:	
	
		# 组装响应的内容
		response_headers = "HTTP/1.1 200 OK
"
		response_headers += "
"
		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
"
		response_headers += "
"
		response_body = b"page not found"
	else:	
	
		# 组装响应的内容
		response_headers = "HTTP/1.1 200 OK
"
		response_headers += "
"
		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()
原文地址:https://www.cnblogs.com/zhangfengxian/p/10182138.html