python之动态服务器初练习

python之动态服务器初练习

首先是简单的应用程序框架

实现原理是根据动态资源不同返回的数据信息
浏览器–1.请求动态资源–服务器–2.wsgi协议调用接口–应用程序框架(Django/flask…)
3.web框架通过引用服务器的方法,设置返回的状态和头信息
4.调用返回,服务器会保存设置信息
5.框架查询数据库,生成动态的页面
6.把生成的动态数据返回给服务器
7.web服务器将数据返回给客户端
中间是必须写接口

以下是实例类实现,类名为application.py(名字和导包有关,用到__import__)

def app(environ, start_response):
'''
:param environ: 跟http请求相关的数据(用户请求路径,请求头),必须是个字典
:param start_response: 函数引用(由服务器提供),作用:设置状态和响应头
    start_response这个函数有两个参数,第一个参数表示状态,第二个参数表示响应
    的头部(列表类型),写在服务器上但是框架上调用
:return:返回值是网页的内容
'''
# 根据不同的请求路径返回不同内容
	request_path = environ['path']
	if request_path == 'index.py':
	    # return_str是我们要返回的网页内容
		return_str = '###########这是主页面##############'
	# elif request_path == 'login.py'  # 这里可以写自己想要区分的内容
	else:
		return_str = '这是动态服务器返回的网页内容'
	# 这个是调用服务器的方法,这里传入内容
	# 参数一表示状态,参数二表示请求内容
	start_response('200 ok'. [('name','paul'), ('age','18)])
	
	return return_str

服务器类:

import socket
import threading
import sys
import re
import chardet

# 这是服务器类可以静态也可以动态调用
class MyServer(object):
	def __init__(self, port, app):
		'''
		:param port:这是端口
		:param app:这个是调用应用框架的方法
		'''
		self.app = app
		# 初始化创建服务器套接字
		self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		# 设定回收端口
		self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
		# 设定绑定端口
		self.server_socket.bind(('', port))
		# 要传输的数据设为属性方便使用
		self.response_data = None
	
	# 启动服务器
	def start(self):
		# 这是监听
		self.server_socket.listen()
		while True:
			# 直接拆包accept()函数得到的内容,第一个是服务套接字,第二个是地址信息
			client_socket, address_info = self.server_socket.accept()
			# 创建一个线程处理客户端的请求
			client_thread = threading.Thread(target=self.handle_client, args=(client_socket,))
			client_thread.start()
	
	def handle_client(self, client_socket):
		# 客户服务
		data = client_socket.recv(1024).decode('utf-8')
		data_list = data.split('\r\n')
		first_line = data_list[0]
		if not first_line:
			#如果没有数据就关闭
			client_socket.close()
			return
		try:
			ret = re.search('GET (/.*?) HTTP1.1', first_line)
			request_path = ret.group(1)
		except:
		    # 如果没有就给一个默认值
			request_path = '/'
		# 判断结尾是否.py 是则进入动态判断
		if request_path.endswith('.py'):
			response_body = self.app(environ={'path':request_path}, self.start_response)
			response = self.response_data + response_body
			client_socket.send(response.encode('gbk'))
		# 不是就静态判断:
		else:
			# 这是默认为正确的状态码,在错误页面改成错误内容
			status_code = '200 ok'
			if request_path == '/' or request_path == '/index.html':
				with open('index.html') as f:
					response_body = f.read()
			elif request_path == '/login.html' :
				with open('cat_head.png' 'rb') as f:  # 这是传输图片内容
					response_body = f.read()  # 注意这里是二进制数据
			else:
				# 这是出错页面
				status_code = '404 not found'
				with open('err.html') as f:
					response_body = f.read()
			# 这里写请求头内容
			response_header = 'HTTP1.1	' + status_code + '\r\n' 
			response_header += '\r\n'  # 这里是静态所以没有内容直接加'\r\n'
			try:
				chardet.detect(response_body)  # 判断是否是二进制
				response_header = response_header.encode('utf-8')
			except:
				response_header = response_header.encode('utf-8')
				response_body = response_body.encode('utf-8')
			finally:
				sent_count = 0  # 这是已经发送数据大小
				self.response_data = response_header + response_body  # 这是要发送的所有数据
				while sent_count < len(self.response_data):
				  	# 这里写的是如果没发送完继续传输,
					now_sendsize = client_socket.send(self.response_data[sent_count:])  # 这是现在发送的数据大小
					sent_count += now_sendsize
				# 传输完关闭客户端套接字
				client_socket.close()

	# 动态判断用的		
	def start_response(self, status, header_list):
		response_header_firstline = 'HTTP1.1' + status + '\r\n'
		response_header = ''
		# 传入的header_list是header键值,直接拆包
		for header_key, header_value in header_list:
			response_header += header_key + header_value +'\r\n'
		self.response_data = response_header_firstline + response_header +'\r\n'
		

def main():
	# 实现主要逻辑
	try:
		# 这个是用端口来启动py文件
		port = sys.argv[1]  # argv是个列表第一个参数是当前执行文件名,之后是你输入的值
		frame_name = sys.argv[2]
	except:
		# 当没有正确输入的时候给个默认值
		print('没有正确输入')
		port = 8000
		frame_name = 'application:app'
	finally:
		frame_list = frame_name.split(':')  # 端口输入内容为application:app,所以要切割
		modle_name = frame_list[0]  # 要导入包的名字
		app_name = frame_list[1]  # 方法名
		ret = __import__(modle_name)  # 这是根据string导包的方式
		app = getattr(ret, app_name)  # 这个方法得到要导方法
		my_server = MyServer(port=int(port), app=app)
		my_server.start()

if __name__ == '__main__':
	main()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值