在本教程中, 添加了一些有趣的功能以使其更有用。
- 将网域加入黑名单。对于前google.com, facebook.com。在我们的配置字典中创建BLACKLIST_DOMAINS的列表。现在, 只需忽略/删除收到的列入黑名单的域的请求即可。 (理想情况下, 我们必须以禁止的回应来回应。)
# Check if the host:port is blacklisted for i in range(0, len(config['BLACKLIST_DOMAINS'])): if config['BLACKLIST_DOMAINS'][i] in url: conn.close() return
- 要添加主机阻止:假设你可能需要允许来自特定子网的连接或特定人的连接。要添加此内容, 请创建所有允许的主机的列表。由于主机也可以是子网, 因此添加正则表达式以匹配IP地址, 尤其是IPV4地址。" IPv4地址以点十进制表示法规范地表示, 它由四个十进制数字组成, 每个数字的范围从0到255, 由点分隔, 例如172.16.254.1。每个部分代表地址的一组8位(八位字节)。"
- 使用正则表达式匹配正确的IP地址:
- 在Server类中创建一个新方法_ishostAllowed, 并使用fnmatch模块来匹配正则表达式。遍历所有正则表达式, 如果匹配任何正则表达式则允许请求。如果没有发现客户地址是任何正则表达式的一部分, 则发送一个FORBIDDEN响应。再次, 现在跳过此响应创建部分。
注意:在接下来的教程中, 我们将创建完整的自定义Web服务器, 在那里将创建createResponse函数来处理通用响应的创建。
def _ishostAllowed(self, host):
""" Check if host is allowed to access
the content """
for wildcard in config['HOST_ALLOWED']:
if fnmatch.fnmatch(host, wildcard):
return True
return False
默认主机匹配正则表达式为" *", 以匹配所有主机。不过, 也可以使用" 192.168。*"形式的正则表达式。服务器当前正在处理请求, 但不显示任何消息, 因此我们不知道服务器的状态。其消息应登录到控制台。为此, 请使用日志记录模块, 因为它是线程安全的。 (如果你记得, 服务器是多线程的。)
导入模块并设置其初始配置。
logging.basicConfig(level = logging.DEBUG, format = '[%(CurrentTime)-10s] (%(ThreadName)-10s) %(message)s', )
- 创建一个单独的方法来记录每条消息:将其作为参数传递, 并带有其他数据, 例如线程名和当前时间, 以跟踪日志。还创建一个使日志着色的函数, 以便在STDOUT上看起来漂亮。
为此, 在配置中添加一个布尔值COLORED_LOGGING并创建一个新函数, 该函数根据LOG_LEVEL为传递给它的每个味精着色。
def log(self, log_level, client, msg):
""" Log the messages to appropriate place """
LoggerDict = {
'CurrentTime' : strftime("%a, %d %b %Y %X", localtime()), 'ThreadName' : threading.currentThread().getName()
}
if client == -1: # Main Thread
formatedMSG = msg
else: # Child threads or Request Threads
formatedMSG = '{0}:{1} {2}'.format(client[0], client[1], msg)
logging.debug('%s', utils.colorizeLog(config['COLORED_LOGGING'], log_level, formatedMSG), extra=LoggerDict)
- 创建一个新模块ColorizePython.py:它包含一个pycolors类, 该类维护一个颜色代码列表。将其分成另一个模块, 以使代码模块化并遵循PEP8标准。
# ColorizePython.py
class pycolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m' # End color
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
模块:
import ColorizePython
方法:
def colorizeLog(shouldColorize, log_level, msg):
## Higher is the log_level in the log()
## argument, the lower is its priority.
colorize_log = {
"NORMAL": ColorizePython.pycolors.ENDC, "WARNING": ColorizePython.pycolors.WARNING, "SUCCESS": ColorizePython.pycolors.OKGREEN, "FAIL": ColorizePython.pycolors.FAIL, "RESET": ColorizePython.pycolors.ENDC
}
if shouldColorize.lower() == "true":
if log_level in colorize_log:
return colorize_log[str(log_level)] + msg + colorize_log['RESET']
return colorize_log["NORMAL"] + msg + colorize_log["RESET"]
return msg
- 由于colorizeLog不是服务器类的函数, 因此将其创建为名为utils.py的单独模块, 该模块存储使代码更易于理解的所有实用程序并将此方法放在此处。在任何需要的地方添加适当的日志消息, 尤其是在服务器状态更改时。
- 在退出应用程序之前, 修改服务器中的关闭方法以退出所有正在运行的线程。threading.enumerate()迭代所有正在运行的线程, 因此我们不需要维护它们的列表。当我们尝试结束main_thread时, 线程模块的行为是意外的。官方文档还指出:
如果试图加入当前线程, join()会引发RuntimeError, 因为这将导致死锁。在线程启动之前加入()线程也是错误的, 尝试这样做会引发相同的异常。"
因此, 请适当跳过它。这是相同的代码。
def shutdown(self, signum, frame):
""" Handle the exiting server. Clean all traces """
self.log("WARNING", -1, 'Shutting down gracefully...')
main_thread = threading.currentThread() # Wait for all clients to exit
for t in threading.enumerate():
if t is main_thread:
continue
self.log("FAIL", -1, 'joining ' + t.getName())
t.join()
self.serverSocket.close()
sys.exit(0)
如果你有任何意见/建议/疑问, 请随时提问。 🙂
关于作者:
Pinkesh Badjatiya来自海得拉巴(IIIT)海德拉巴。可见他的项目工作这里。
如果你还希望在此处展示你的博客, 请参阅日志用于在lsbin上撰写访客博客。
首先, 你的面试准备可通过以下方式增强你的数据结构概念:Python DS课程。