目录
一、面向对象封装
二、给服务器加上命令行参数
三、植物大战僵尸小游戏服务器
一、面向对象封装
在上一篇博客基础上进行面向对象封装。
代码:
import socket
from threading import Thread
class WebServer(object):
# 初始化方法
def __init__(self):
# 创建套接字
self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置地址重用 SOL_SOCKET表示当前套接字,SO_REUSEADDR表示设置地址重用
self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定端口
self.tcp_server_socket.bind(("", 8080))
# 设置监听,让套接字由主动变为被动接收
self.tcp_server_socket.listen(128)
def start(self):
""" 启动Web服务器 """
while True:
# 接收客户端连接 定义函数
new_client_socket, ip_port = self.tcp_server_socket.accept()
print("新的客户端%s已连接!" % str(ip_port))
# 接收请求并作出响应
t1 = Thread(target=self.request_handler, args=(new_client_socket, ip_port))
t1.start()
def request_handler(self, new_client_socket, ip_port):
"""接收信息,并且做出响应"""
# 接收客户端浏览器发送的请求协议
request_data = new_client_socket.recv(1024) # 接收请求报文
# print(request_data)
# 判断协议是否为空
if not request_data:
print("%s客户端已下线!" % str(ip_port))
new_client_socket.close()
else:
# 根据客户端浏览器请求的资源路径,返回请求资源
# 1.把请求协议解码,得到请求报文的字符串
request_text = request_data.decode()
# 2.得到请求行
# 2.1 查找 第一个\r\n出现的位置
loc = request_text.find("\r\n")
# 2.2 截取字符串,从开头截取到 第一个\r\n出现的位置
request_line = request_text[:loc]
# print(request_line)
# 2.3 把请求行按照空格拆分,得到列表
request_line_list = request_line.split(" ")
# 2.4 得到请求资源路径
file_path = request_line_list[1]
print("%s 正在请求:%s" % (str(ip_port), file_path))
# 响应行
response_line = "HTTP/1.1 200 OK\r\n"
# 响应头
response_header = "Server:Python20WS/2.1\r\n"
# 响应空行
response_blank = "\r\n"
# 响应主体
# 返回字符串内容
# response_body = "Hello World"
# 返回固定页面
try:
with open("static" + file_path, "rb") as file:
response_body = file.read()
except Exception as e:
# 重新修改响应行为 404
response_line = "HTTP/1.1 404 Not Found\r\n"
response_body = "Error! %s " % str(e)
response_body = response_body.encode()
# 拼接响应报文
response_data = (response_line + response_header + response_blank).encode() + response_body
# 发送响应报文
new_client_socket.send((response_data))
# 关闭连接
new_client_socket.close()
if __name__ == '__main__':
WS = WebServer()
WS.start()
二、给服务器加上命令行参数
import socket,sys
from threading import Thread
class WebServer(object):
# 初始化方法
def __init__(self, port):
# 创建套接字
self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置地址重用 SOL_SOCKET表示当前套接字,SO_REUSEADDR表示设置地址重用
self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定端口
self.tcp_server_socket.bind(("", port))
# 设置监听,让套接字由主动变为被动接收
self.tcp_server_socket.listen(128)
def start(self):
""" 启动Web服务器 """
while True:
# 接收客户端连接 定义函数
new_client_socket, ip_port = self.tcp_server_socket.accept()
print("新的客户端%s已连接!" % str(ip_port))
# 接收请求并作出响应
t1 = Thread(target=self.request_handler, args=(new_client_socket, ip_port))
t1.start()
def request_handler(self, new_client_socket, ip_port):
"""接收信息,并且做出响应"""
# 接收客户端浏览器发送的请求协议
request_data = new_client_socket.recv(1024) # 接收请求报文
# print(request_data)
# 判断协议是否为空
if not request_data:
print("%s客户端已下线!" % str(ip_port))
new_client_socket.close()
else:
# 根据客户端浏览器请求的资源路径,返回请求资源
# 1.把请求协议解码,得到请求报文的字符串
request_text = request_data.decode()
# 2.得到请求行
# 2.1 查找 第一个\r\n出现的位置
loc = request_text.find("\r\n")
# 2.2 截取字符串,从开头截取到 第一个\r\n出现的位置
request_line = request_text[:loc]
# print(request_line)
# 2.3 把请求行按照空格拆分,得到列表
request_line_list = request_line.split(" ")
# 2.4 得到请求资源路径
file_path = request_line_list[1]
print("%s 正在请求:%s" % (str(ip_port), file_path))
# 响应行
response_line = "HTTP/1.1 200 OK\r\n"
# 响应头
response_header = "Server:Python20WS/2.1\r\n"
# 响应空行
response_blank = "\r\n"
# 响应主体
# 返回字符串内容
# response_body = "Hello World"
# 返回固定页面
try:
with open("static" + file_path, "rb") as file:
response_body = file.read()
except Exception as e:
# 重新修改响应行为 404
response_line = "HTTP/1.1 404 Not Found\r\n"
response_body = "Error! %s " % str(e)
response_body = response_body.encode()
# 拼接响应报文
response_data = (response_line + response_header + response_blank).encode() + response_body
# 发送响应报文
new_client_socket.send((response_data))
# 关闭连接
new_client_socket.close()
def main():
# 获取系统传递到程序的参数
params_list = sys.argv
# print(params_list)
# 判断参数个数
if len(params_list) != 2:
print("启动失败,正确启动格式:python xxx.py port")
# 判断端口号是否为纯数字
if not params_list[1].isdigit():
print("启动失败,端口号应为纯数字")
port = int(params_list[1])
WS = WebServer(port)
WS.start()
if __name__ == '__main__':
main()
结果:
三、植物大战僵尸小游戏服务器
项目结构:
服务端代码:
import socket,sys
class WebServer(object):
# 初始化方法
def __init__(self, port):
# 创建套接字
self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置地址重用 SOL_SOCKET表示当前套接字,SO_REUSEADDR表示设置地址重用
self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定端口
self.tcp_server_socket.bind(("", port))
# 设置监听,让套接字由主动变为被动接收
self.tcp_server_socket.listen(128)
self.project_dict = {}
self.project_dict["足球大战僵尸"] = "h5-game-footballVSzombies"
self.project_dict["植物大战僵尸"] = "h5-game-plantsVSzombies"
self.current_dir = ""
self.init_projects()
def init_projects(self):
# 显示所有的游戏名称
key_list = list(self.project_dict.keys()) # 取出字典的key并且转换成列表
for index, gameName in enumerate(key_list):
print("%d.%s" % (index, gameName))
# 接收用户的选择
sel_no = int(input("请选择游戏序号:\n"))
# 根据用户的选择来运行指定游戏
key = key_list[sel_no]
# 根据key得到项目路径
self.current_dir = self.project_dict[key]
print(key, self.current_dir)
def start(self):
""" 启动Web服务器 """
print("网游服务器已启动!")
while True:
# 接收客户端连接 定义函数
new_client_socket, ip_port = self.tcp_server_socket.accept()
print("新的客户端%s已连接!" % str(ip_port))
# 接收请求并作出响应
self.request_handler(new_client_socket, ip_port)
def request_handler(self, new_client_socket, ip_port):
"""接收信息,并且做出响应"""
# 接收客户端浏览器发送的请求协议
request_data = new_client_socket.recv(1024) # 接收请求报文
# print(request_data)
# 判断协议是否为空
if not request_data:
print("%s客户端已下线!" % str(ip_port))
new_client_socket.close()
else:
# 根据客户端浏览器请求的资源路径,返回请求资源
# 1.把请求协议解码,得到请求报文的字符串
request_text = request_data.decode()
# 2.得到请求行
# 2.1 查找 第一个\r\n出现的位置
loc = request_text.find("\r\n")
# 2.2 截取字符串,从开头截取到 第一个\r\n出现的位置
request_line = request_text[:loc]
# print(request_line)
# 2.3 把请求行按照空格拆分,得到列表
request_line_list = request_line.split(" ")
# 2.4 得到请求资源路径
file_path = request_line_list[1]
print("%s 正在请求:%s" % (str(ip_port), file_path))
if file_path == "/":
file_path = "/index.html"
# 响应行
response_line = "HTTP/1.1 200 OK\r\n"
# 响应头
response_header = "Server:Python20WS/2.1\r\n"
# response_header = response_header + "Content-Type: text/html\r\n"
# 响应空行
response_blank = "\r\n"
# 响应主体
# 返回字符串内容
# response_body = "Hello World"
# 返回固定页面
try:
with open(self.current_dir + file_path, "rb") as file:
response_body = file.read()
except Exception as e:
# 重新修改响应行为 404
response_line = "HTTP/1.1 404 Not Found\r\n"
response_body = "Error! %s " % str(e)
response_body = response_body.encode()
# 拼接响应报文
response_data = (response_line + response_header + response_blank).encode() + response_body
# 发送响应报文
new_client_socket.send((response_data))
# 关闭连接
new_client_socket.close()
def main():
# 获取系统传递到程序的参数
params_list = sys.argv
# print(params_list)
# 判断参数个数
if len(params_list) != 2:
print("启动失败,正确启动格式:python xxx.py port")
# 判断端口号是否为纯数字
if not params_list[1].isdigit():
print("启动失败,端口号应为纯数字")
port = int(params_list[1])
WS = WebServer(port)
WS.start()
if __name__ == '__main__':
main()
效果:
前端代码下载地址: