如果您对oracle服务启动,关闭脚本(windows系统下)感兴趣,那么本文将是一篇不错的选择,我们将为您详在本文中,您将会了解到关于oracle服务启动,关闭脚本(windows系统下)的详细内容
如果您对oracle 服务启动,关闭脚本(windows系统下)感兴趣,那么本文将是一篇不错的选择,我们将为您详在本文中,您将会了解到关于oracle 服务启动,关闭脚本(windows系统下)的详细内容,我们还将为您解答oracle服务关闭命令的相关问题,并且为您提供关于Android 源码 图形系统之 SurfaceFlinger 服务启动、Apache开启gzip压缩功能(windows系统下)、Centos 命令行 配置 服务启动 ntsysv、django 源码分析 --01 服务启动 (wsgi)的有价值信息。
本文目录一览:- oracle 服务启动,关闭脚本(windows系统下)(oracle服务关闭命令)
- Android 源码 图形系统之 SurfaceFlinger 服务启动
- Apache开启gzip压缩功能(windows系统下)
- Centos 命令行 配置 服务启动 ntsysv
- django 源码分析 --01 服务启动 (wsgi)
oracle 服务启动,关闭脚本(windows系统下)(oracle服务关闭命令)
Windows下的批出理程序,就是dos命令的集合,我们也可以通过运行程序里的命令来开启服务.
一.概念简介脚本:script是使用一种特定的描述性语言,依据一定的格式编写的可执行文件,又称作宏或文件。
二.背景
近来在Windows下安装了
三.正文
1.利用资源管理器关闭相关进程如oracle.exe,这种方式需要我们非常了解oracle的进程控制程序。
2.利用windows的控制面板管理。步骤:
开始->控制面板->性能和维护->管理工具->服务 然后找到相关以oracle开头的服务,我的系统下如下:
OracleDBConsoleoracle
OracleJobSchedulerORACLE
OracleOraDb10g_home1iSQL*Plus
OracleOraDb10g_home1TNSListener
OracleServiceORACLE
对这些服务进行启动停止等操作。
3.利用脚本,即程序。
我们可以如2,将系统里的
OracleOraDb10g_home1iSQL*Plus
OracleOraDb10g_home1TNSListener
OracleServiceORACLE
这三项设为手动,这样开机就不会启动这三项服务,开机会更快。
然后,我们建立程序:
1.建立dbstart.cmd文件(开启)
2.添加如下内容:
代码如下:
@echo off
net start OracleServiceORACLE
net start OracleOraDb10g_home1iSQL*Plus
net start OracleOraDb10g_home1TNSListener
pause
同样我们可以建立关闭文件(dbstop.cmd)
@echo off
net stop OracleServiceORACLE
net stop OracleOraDb10g_home1iSQL*Plus
net stop OracleOraDb10g_home1TNSListener
pause
这样我们就可以双击这两个文件来开启或关闭oracle的服务程序。
(朋友可能注意到3里面用到的服务正是2里面查找到的服务,确实2也是一种查找自己系统服务的方法)
四.总结
1.Windows下的批出理程序,就是dos命令的集合,我们也可以通过运行程序里的命令来开启服务.
2.熟悉Linux的朋友一定会知道Linux下的shell脚本也是命令的集合,通过脚本我们可以将常用的命令集合写成脚本.这在管理系统的时候非常高效。
Android 源码 图形系统之 SurfaceFlinger 服务启动
SurfaceFlinger 服务起点在 init.rc 中。boot Action 中最后 class_start 命令启动了分类为 core 的所有服务,这其中就包括 surfaceflinger。
system/core/rootdir/init.rc
on boot
......
class_start core
......
service surfaceflinger /system/bin/surfaceflinger
class core
user system
group graphics drmrpc
onrestart restart zygote
writepid /dev/cpuset/system-background/tasks
现在来确定 surfaceflinger 服务源码位置。在以下 Android.mk 中,我们发现起点位于 main_surfaceflinger.cpp。
frameworks/native/services/surfaceflinger/Android.mk
###############################################################
# build surfaceflinger''s executable
include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_LDFLAGS := -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic
LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
LOCAL_CPPFLAGS := -std=c++11
LOCAL_SRC_FILES := \
main_surfaceflinger.cpp
LOCAL_SHARED_LIBRARIES := \
libsurfaceflinger \
libcutils \
liblog \
libbinder \
libutils \
libdl
LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
LOCAL_MODULE := surfaceflinger
ifdef TARGET_32_BIT_SURFACEFLINGER
LOCAL_32_BIT_ONLY := true
endif
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
include $(BUILD_EXECUTABLE)
###############################################################
重点关注 SurfaceFlinger 实例化,以及 init() 方法,其 run() 方法在《Android 源码 图形系统之 relayoutWindow》一节中已经介绍过了。
frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp
using namespace android;
int main(int, char**) {
// 在以自己的进程启动 SF 时,将绑定程序线程数限制为4。
ProcessState::self()->setThreadPoolMaxThreadCount(4);
// 启动线程池
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
// 实例化 SurfaceFlinger
sp<SurfaceFlinger> flinger = new SurfaceFlinger();
setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
set_sched_policy(0, SP_FOREGROUND);
// 在客户端连接之前初始化
flinger->init();
// 发布 surface flinger
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
// 在此线程中运行
flinger->run();
return 0;
}
SurfaceFlinger 类无参构造器中初始化了一系列参数。onFirstRef() 方法中初始化了 mEventQueue(MessageQueue)。
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(),
mTransactionFlags(0),
mTransactionPending(false),
mAnimTransactionPending(false),
mLayersRemoved(false),
mRepaintEverything(0),
mRenderEngine(NULL),
mBootTime(systemTime()),
mVisibleRegionsDirty(false),
mHwWorkListDirty(false),
mAnimCompositionPending(false),
mDebugRegion(0),
mDebugDDMS(0),
mDebugDisableHWC(0),
mDebugDisableTransformHint(0),
mDebugInSwapBuffers(0),
mLastSwapBufferTime(0),
mDebugInTransaction(0),
mLastTransactionTime(0),
mBootFinished(false),
mForceFullDamage(false),
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
mDaltonize(false),
mHasColorMatrix(false),
mHasPoweredOff(false),
mFrameBuckets(),
mTotalTime(0),
mLastSwapTime(0)
{
ALOGI("SurfaceFlinger is starting");
// 调试的东西……
char value[PROPERTY_VALUE_MAX];
property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
mGpuToCpuSupported = !atoi(value);
property_get("debug.sf.drop_missed_frames", value, "0");
mDropMissedFrames = atoi(value);
property_get("debug.sf.showupdates", value, "0");
mDebugRegion = atoi(value);
property_get("debug.sf.ddms", value, "0");
mDebugDDMS = atoi(value);
if (mDebugDDMS) {
if (!startDdmConnection()) {
// 启动失败,DDMS 调试未启用
mDebugDDMS = 0;
}
}
ALOGI_IF(mDebugRegion, "showupdates enabled");
ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
}
void SurfaceFlinger::onFirstRef()
{
mEventQueue.init(this);
}
MessageQueue::init(…) 方法中初始化了 mFlinger、mLooper 和 mHandler。
frameworks/native/services/surfaceflinger/MessageQueue.cpp
void MessageQueue::init(const sp<SurfaceFlinger>& flinger)
{
mFlinger = flinger;
mLooper = new Looper(true);
mHandler = new Handler(*this);
}
SurfaceFlinger 初始化工作在代码中已经详细注释过了。
frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger''s main thread ready to run. "
"Initializing graphics H/W...");
Mutex::Autolock _l(mStateLock);
// 为默认显示初始化 EGL
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(mEGLDisplay, NULL, NULL);
// 启动 EventThread
sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
vsyncPhaseOffsetNs, true, "app");
mEventThread = new EventThread(vsyncSrc);
sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
sfVsyncPhaseOffsetNs, true, "sf");
mSFEventThread = new EventThread(sfVsyncSrc);
mEventQueue.setEventThread(mSFEventThread);
// 初始化 H/W composer 对象。下面可能有也可能没有实际的硬件 composer。
mHwc = new HWComposer(this,
*static_cast<HWComposer::EventHandler *>(this));
// 为给定的显示/配置获得一个 RenderEngine 渲染引擎(不会失败)
mRenderEngine = RenderEngine::create(mEGLDisplay, mHwc->getVisualID());
// 检索被选择/创建的 EGL 上下文
mEGLContext = mRenderEngine->getEGLContext();
LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
"couldn''t create EGLContext");
// 初始化非虚拟显示
for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
// 设置已经连接的显示器
if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
// 目前,所有非虚拟显示都被认为是安全的。
bool isSecure = true;
createBuiltinDisplayLocked(type);
wp<IBinder> token = mBuiltinDisplays[i];
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
// 创建 BufferQueue
BufferQueue::createBufferQueue(&producer, &consumer,
new GraphicBufferAlloc());
sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
consumer);
int32_t hwcId = allocateHwcDisplayId(type);
sp<DisplayDevice> hw = new DisplayDevice(this,
type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
fbs, producer,
mRenderEngine->getEGLConfig());
if (i > DisplayDevice::DISPLAY_PRIMARY) {
// FIXME: currently we don''t get blank/unblank requests
// for displays other than the main display, so we always
// assume a connected display is unblanked.
ALOGD("marking display %zu as acquired/unblanked", i);
hw->setPowerMode(HWC_POWER_MODE_NORMAL);
}
mDisplays.add(token, hw);
}
}
// 使 GLContext 为最新,以便我们在创建图层时可以创建纹理(这可能在渲染某些东西之前发生)
getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);
mEventControlThread = new EventControlThread(this);
mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
// 如果没有 HWComposer,设置一个假的垂直同步周期
if (mHwc->initCheck() != NO_ERROR) {
mPrimaryDispSync.setPeriod(16666667);
}
// 初始化我们的绘制状态
mDrawingState = mCurrentState;
// 设置初始条件(如取消默认设备)
initializeDisplays();
// 开始启动动画
startBootAnim();
}
Apache开启gzip压缩功能(windows系统下)
Apache的gzip功能开启主要都是通过修改Apache的配置文件。
为什么要开启Gzip?
答:Gzip开启以后会将输出到用户浏览器的数据进行压缩的处理,这样就会减小通过网络传输的数据量,提高浏览的速度。
如何开启Gzip?
下面就主要以图片进行说明同时配以简单的文字说明。
1. 先找到httpd.conf文件,对于XAMPP套件,这个文件位于: %XAMPP安装目录%\apache\conf\ 目录下
2. 开启gzip功能。XAMPP的Apache提供支gzip功能,但是名字是叫mod_deflate,默认是没有开启的。所以首先要开始gzip功能。
gzip功能是使用mod_deflate.so模块,第一步要做的就是引入mod_deflate.so模块:
首先打开 httpd.conf 文件, 然后搜索找到 mod_deflate.so 这一行,然后去掉这一行前面的 "#" 注释符号。
3. 配置gzip,放到http.conf最后一行。 一般要进行gzip的文件是一些常见的web文件文件,如 js,css等。
1
2
3
4
5
|
<IfModule mod_deflate.c>
DeflateCompressionLevel 9
SetOutputFilter DEFLATE
AddOutputFilter DEFALTE html xml php js css png jpg gif
</IfModule>
|
4. 重启Apache。 然后去浏览器测试一下效果。下面是我的一些效果截图:
大家可以从图中看到,效果非常惊人,压缩率达到了 76.7% ,效果非常明显。
Centos 命令行 配置 服务启动 ntsysv

yum install ntsysv
然后 使用 ntsysv
就有界面可以配置 启动停止的 服务了。
django 源码分析 --01 服务启动 (wsgi)
环境说明
- [x] Python 3.5
- [x] Django 1.10.4
创建一个 django 项目
C:\Users\zhengtong>C:\Python35\Scripts\django-admin.exe startproject HelloWorld
项目文件结构
├── HelloWorld
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py
初始化项目
C:\Users\zhengtong>cd HelloWorld
C:\Users\zhengtong\HelloWorld>C:\Python35\python.exe manage.py migrate # 创建数据库表(默认是采用的sqlite3).
C:\Users\zhengtong\HelloWorld>C:\Python35\python.exe manage.py createsuperuser # 创建管理员用户, 该用户用来django提供的admin登录管理界面.
启动项目
C:\Users\zhengtong\HelloWorld>C:\Python35\python.exe manage.py runserver
启动项目服务,默认监听的端口是 localhost:8000,也就是说打开浏览器,输入 http://localhost:8000 就可以访问到 HelloWorld 这个项目网站了。
还有就是在浏览器中输入 http://localhost:8000/admin 可以访问到 django 提供的 admin 登录管理界面。
Django Management
Django 框架的整个数据流向、服务启动、端口监听等基础核心功能都是按照 WSGI 标准进行开发的。WSGI 是 Web Server Gateway Interface 的缩写,它的主要作用是接收客户端 (浏览器 / 软件 / APP / 调试程序) 发送的请求和转发请求给上层服务 (例如 Django)。它采用了 select 网络模型进行数据的接收和分发,可以利用操作系统的非堵塞和线程池等特性,因此它是非常高效的 (Django 采用 wsgi 是纯 python 代码实现,开源项目有一个 uWSGI 是 C 语言代码实现,因此现在更多的 django 项目实际上是运行在 uWSGI 上的,uWSGI 不再讨论范围之内)。
接下来是记录我利用 pycharm 提供的断点调试功能以及自己打日志整个过程的梳理和总结。
源码的分析过程取决与分析人员想要关注的原理点,不同的需求就会有不同的侧重点,我当前的需求点是,想要知道 django 是如何通过网络层接收数据 (wsgi) 并将请求转发给 django 的 urls 层,因此我会朝着这个主题方向列出每个流转环节中的核心代码并做相应的注解。以后如果有机会的话我将会从另外一个侧重点 (程序设计) 去分析源码。
每个过程我都会先将代码列出来然后在后面做注解,因此告诫自己以后重读自己的笔记时不需要努力的去看代码,而是直接看注解,然后找到对应的代码进行理解。
代码块我会用... 来忽略掉一些跟主题无关的代码。
manage.py
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "TestDrivenDjango.settings")
try:
from django.core.management import execute_from_command_line
except ImportError:
...
execute_from_command_line(sys.argv)
from django.core.management import execute_from_command_line
当这行代码开始执行时,首先会去运行 django.core.management.__init__.py
这一整个文件,接着找到 execute_from_command_line
函数并将其导入到当前程序的命名空间中。
由于整个 django.core.management.__init__.py
文件都是 class
类对象和 function
函数对象,很多时候很自然的就认为这个文件并没有执行任何命令,只是加载了这些个对象,然后在这些个对象中寻找是否包含有 execute_from_command_line
。最终忽视了其他很重要的代码块 ==from 和 import==。
django/core/management/__init__.py
from __future__ import unicode_literals
import os
import pkgutil
import sys
from collections import OrderedDict, defaultdict
from importlib import import_module
import django # 这里
from django.apps import apps # 这里
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.management.base import (
BaseCommand, CommandError, CommandParser, handle_default_options,
)
from django.core.management.color import color_style
from django.utils import autoreload, lru_cache, six
from django.utils._os import npath, upath
from django.utils.encoding import force_text
@lru_cache.lru_cache(maxsize=None)
def get_commands():
commands = {name: ''django.core'' for name in find_commands(upath(__path__[0]))}
if not settings.configured:
return commands
for app_config in reversed(list(apps.get_app_configs())):
path = os.path.join(app_config.path, ''management'')
commands.update({name: app_config.name for name in find_commands(path)})
return commands
class ManagementUtility(object):
def __init__(self, argv=None):
...
def fetch_command(self, subcommand):
commands = get_commands()
try:
app_name = commands[subcommand]
except KeyError:
...
if isinstance(app_name, BaseCommand):
klass = app_name
else:
klass = load_command_class(app_name, subcommand)
return klass
def execute(self):
...
if subcommand == ''help'':
if ''--commands'' in args:
sys.stdout.write(self.main_help_text(commands_only=True) + ''\n'')
elif len(options.args) < 1:
sys.stdout.write(self.main_help_text() + ''\n'')
else:
self.fetch_command(options.args[0]).print_help(self.prog_name, options.args[0])
elif subcommand == ''version'' or self.argv[1:] == [''--version'']:
sys.stdout.write(django.get_version() + ''\n'')
elif self.argv[1:] in ([''--help''], [''-h'']):
sys.stdout.write(self.main_help_text() + ''\n'')
else:
self.fetch_command(subcommand).run_from_argv(self.argv)
def execute_from_command_line(argv=None):
"""
A simple method that runs a ManagementUtility.
"""
utility = ManagementUtility(argv)
utility.execute()
import django
这行代码运行了 django.__init__.py
文件。
from django.apps import apps
这行代码运行了 django.apps.__init__.py
文件,然而整个 django 的开端就是从这里开始的,它落实了非常多的事情(例如:初始化日志模块、加载 INSTALL_APP、检查各 APP 是否正常、检查缓存模块是否正常等),当一切无误时才会往下走,否则将会报错退出程序。
execute_from_command_line
这个方法是一个工厂函数,它负责指挥 ManagementUtility 类利用 execute
方法来解析参数和启动 wsgi 服务。
ManagementUtility.execute
方法中的一大堆 if 条件就是判断参数是否合法,重点还是在 self.fetch_command(subcommand).run_from_argv(self.argv)
,这条命令应该拆成两部分去看。
- self.fetch_command
是利用 django 内置的命令管理工具去匹配到具体的模块,例如self.fetch_command(subcommand)
其实就相当于是self.fetch_command(''runserver'')
,它最终找到了 ==django.contrib.staticfiles.management.commands.runserver.Command== 这个命令工具。
django 中的命令工具代码组织采用的是策略模式 + 接口模式,也就是说django.core.management.commands
这个目录下面存在各种命令工具,每个工具下面都有一个 Command 接口,当匹配到 ''runserver'' 时调用 ''runserver'' 命令工具的 Command 接口,当匹配到 ''migrate'' 时调用 ''migrate'' 命令工具的 Command 接口。 - run_from_argv(self.argv)
run_from_argv 的作用是初始化中间件、启动服务,也就是拉起 wgsi (但实际上并不是由它来直接完成,而是由后续很多其他代码来完成),直观上看它应该是 runserver.Command 对象的一个方法,但实际上要稍微更复杂一些,因为没有列出关联代码,所以在下一个代码块中进行说明。
小结
这部分代码实际上是一个匹配命令工具的一个过程,通过提供的参数 ''runserver'' 到命令工具集中去找到 runserver 模块。
django/contrib/staticfiles/management/commands/runserver.py
from django.contrib.staticfiles.handlers import StaticFilesHandler
from django.core.management.commands.runserver import \
Command as RunserverCommand
class Command(RunserverCommand):
def add_arguments(self, parser):
super(Command, self).add_arguments(parser)
parser.add_argument(
''--nostatic'', action="store_false", dest=''use_static_handler'', default=True,
help=''Tells Django to NOT automatically serve static files at STATIC_URL.'',
)
parser.add_argument(
''--insecure'', action="store_true", dest=''insecure_serving'', default=False,
help=''Allows serving static files even if DEBUG is False.'',
)
def get_handler(self, *args, **options):
handler = super(Command, self).get_handler(*args, **options)
use_static_handler = options[''use_static_handler'']
insecure_serving = options[''insecure_serving'']
if use_static_handler and (settings.DEBUG or insecure_serving):
return StaticFilesHandler(handler)
return handler
虽然它一共只有两个方法,但是它继承了 django.core.management.commands.runserver.Command
,因此实际上它有非常多的‘方法’可以被调用。由于请求入口在这里,所以后续有调用 ==get_handler== 的地方需要优先看这里,因为这非常容易混淆,我就混淆了好多次。
小结
当前类对象中不存在 run_from_argv
方法,因此我们要往下看它的继承对象 django.core.management.commands.runserver.Command
。
django/core/management/commands/runserver.py
from django.core.servers.basehttp import get_internal_wsgi_application, run
class Command(BaseCommand):
def execute(self, *args, **options):
if options[''no_color'']:
os.environ[str("DJANGO_COLORS")] = str("nocolor")
super(Command, self).execute(*args, **options)
def get_handler(self, *args, **options):
return get_internal_wsgi_application()
def handle(self, *args, **options):
...
self.run(**options)
def run(self, **options):
use_reloader = options[''use_reloader'']
if use_reloader:
autoreload.main(self.inner_run, None, options)
else:
self.inner_run(None, **options)
def inner_run(self, *args, **options):
...
try:
handler = self.get_handler(*args, **options)
run(self.addr, int(self.port), handler,
ipv6=self.use_ipv6, threading=threading)
except socket.error as e:
...
小结
当前这个类对象中也没有 run_from_argv
这个方法,因此我们要往下看它的继承对象 django.core.management.base.BaseCommand
。
django/core/management/base.py
class BaseCommand(object):
def run_from_argv(self, argv):
...
try:
self.execute(*args, **cmd_options)
except Exception as e:
...
finally:
connections.close_all()
def execute(self, *args, **options):
...
try:
...
output = self.handle(*args, **options)
...
finally:
if saved_locale is not None:
translation.activate(saved_locale)
return output
runserver 继承对象分布 依次按顺序如下
django.contrib.staticfiles.management.commands.runserver.Command
django.core.management.commands.runserver.Command
django.core.management.base.BaseCommand
object
当前类对象的 run_from_argv
方法中调用了 self.execute
方法,== 由于请求的入口是 django.contrib.staticfiles.management.commands.runserver.Command
对象 ==,因此 python 并不会去执行 BaseCommand.execute
而是执行 django.core.management.commands.runserver.Command.execute
,最后通过 super(Command, self).execute(*args, **options)
来执行 BaseComand.execute
。
代码流向
由于接下来的代码重度使用了继承、多态、接口等设计模式的方式来运作,没办法做过多解释,所以这里列出了它的一个基本流转过程。
-
BaseComand.execute
方法中调用了self.handle
(即:django.core.management.commands.runserver.Command.handle
)。 -
Command.handle
方法中调用了self.run
(即:django.core.management.commands.runserver.Command.run
)。 -
Command.run
方法调用了self.inner_run
(即:django.core.management.commands.runserver.Command.inner_run
)。 -
Command.inner_run
方法调用了self.get_handler
(即:==django.contrib.staticfiles.management.commands.runserver.Command.get_handler==)
这里要特别强调一下 self.get_handler,它非常重要,三个重点:
- 因为它负责获取 WSGIHandler。
- 由于请求入口是
django.contrib.staticfiles.management.commands.runserver.Command
,整好它本来就有get_handler
这个方法,因此并没有采用django.core.management.commands.runserver.Command.get_handler
。 - self.get_handler 并不会返回一个常规的
WSGIHandler
而是返回一个StaticFilesHandler
。 -
StaticFilesHandler
类对象继承WSGIHandler
,它的目的是为了判断每个请求,如果是常规的 url 请求则直接分配到某个 view 中去执行,如果是静态文件规则那么将不会找 view 而是响应这个文件。
-
Command.inner_run
方法调用了run
(即:django.core.servers.basehttp.run
),由于没有列出代码块,因此在下一个环节中进行说明。
小结
这部分代码实际上就是一个初始化过程,全部都为 ''runserver'' 服务,虽然很多代码我没有列出来,但是它确实做了一些,例如参数解析、端口指定检测、ipv4 检测、ipv6 检测、端口是否占用、线程检查等工作。
django/core/servers/basehttp.py
from wsgiref import simple_server
from django.utils.six.moves import socketserver
class WSGIServer(simple_server.WSGIServer, object):
request_queue_size = 10
def __init__(self, *args, **kwargs):
if kwargs.pop(''ipv6'', False):
self.address_family = socket.AF_INET6
self.allow_reuse_address = kwargs.pop(''allow_reuse_address'', True)
super(WSGIServer, self).__init__(*args, **kwargs)
def server_bind(self):
super(WSGIServer, self).server_bind()
self.setup_environ()
def handle_error(self, request, client_address):
if is_broken_pipe_error():
logger.info("- Broken pipe from %s\n", client_address)
else:
super(WSGIServer, self).handle_error(request, client_address)
class WSGIRequestHandler(simple_server.WSGIRequestHandler, object):
def address_string(self):
return self.client_address[0]
def run(addr, port, wsgi_handler, ipv6=False, threading=False):
server_address = (addr, port)
if threading:
httpd_cls = type(str(''WSGIServer''), (socketserver.ThreadingMixIn, WSGIServer), {}) # Work Here
else:
httpd_cls = WSGIServer
httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
if threading:
httpd.daemon_threads = True
httpd.set_app(wsgi_handler)
httpd.serve_forever()
django.core.servers.basehttp.run
工厂函数负责只会各个对象负责启动 wsgi 服务。wsgi_handler
参数,这里传递的是 StaticFilesHandler
。
type(str(''WSGIServer''), (socketserver.ThreadingMixIn, WSGIServer), {})
是一种很特殊的写法,通过代码块中 WSGIServer 类对象可以看出它只继承了 wsgiref.simple_server.WSGIServer、object 这两个类对象,但是通过 type 这种写法相当于是强行赋予它一个 socketserver.ThreadingMixIn 继承对象,它的用意是每次调用这个对象的时候都会单独启用一个线程来处理。另外虽然 WSGIServer 只继承了 wsgiref.simple_server.WSGIServer、object 两个对象,但是 wsgiref.simple_server.WSGIServer 却 <递归式> 的继承了一堆对象,下面完整的列出 WSGIServer 继承家族。
django.core.servers.basehttp.WSGIServer
-
wsgiref.simple_server.WSGIServer
、socketserver.ThreadingMixIn
http.server.HTTPServer
socketserver.TCPServer
socketserver.BaseServer
object
httpd_cls
这个变量被定义完成之后,由于大量的继承关系,它其实已经不单纯的属于 django,它是一个传统意义上的 WSGI 服务对象了。
httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
这行代码非常重要,因为它是 WSGI 服务器与 django 之间相互通信的唯一枢纽通道,也就是说,当 WSGI 服务对象收到 socket 请求后,会将这个请求传递给 django 的 WSGIRequestHandler (下节会列出 WSGIRequestHandler 是如何工作的)。
httpd.set_app(wsgi_handler)
是将 django.contrib.staticfiles.handlers.StaticFilesHandler
传递给 WSGIServer 当作一个 application,当 WSGIServer 收到网络请求后,可以将数据分发给 django.core.servers.basehttp.WSGIRequestHandler
,最终由 django.core.servers.basehttp.WSGIRequestHandler
将数据传递给 application (即:django.contrib.staticfiles.handlers.StaticFilesHandler
)。
httpd.serve.forever()
启动非堵塞网络监听服务。
总结
上面所有的过程都是 django 内部代码的为了启动服务而做的准备,简单的把流程给列出来。
- 解析运行 python manage.py 所提供的参数,例如: runserver.
- 根据参数 找到相对应的 命令管理工具。
- 加载所有的 app。
- 检查端口、ipv4 检测、ipv6 检测、端口是否占用、线程检查、orm 对象检查 (表是否创建)。
- 实例化 WSGIRequestHandler,并且将它注册到 python Lib 库中的 WSGIServer 中。
- 最后启动 python Lib 库中的 WSGIServer。
WSGIServer To Django WSGIRequestHandler
接下来的部分是 python Lib 库中的 WSGIServer 运作过程中,如何将接收到的请求分发会 django 的 WSGIRequestHandler。
C:/Python35/Lib/socketserver.py
class BaseServer:
def __init__(self, server_address, RequestHandlerClass):
self.server_address = server_address
self.RequestHandlerClass = RequestHandlerClass
self.__is_shut_down = threading.Event()
self.__shutdown_request = False
def serve_forever(self, poll_interval=0.5):
self.__is_shut_down.clear()
try:
with _ServerSelector() as selector:
selector.register(self, selectors.EVENT_READ)
while not self.__shutdown_request:
ready = selector.select(poll_interval)
if ready:
self._handle_request_noblock() # 这里
self.service_actions()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
def _handle_request_noblock(self):
try:
request, client_address = self.get_request()
except OSError:
return
if self.verify_request(request, client_address):
try:
self.process_request(request, client_address) # 这里
except:
self.handle_error(request, client_address)
self.shutdown_request(request)
else:
self.shutdown_request(request)
def verify_request(self, request, client_address):
"""Verify the request. May be overridden.
Return True if we should proceed with this request.
"""
return True
def process_request(self, request, client_address):
self.finish_request(request, client_address) # 这里
self.shutdown_request(request)
def finish_request(self, request, client_address):
self.RequestHandlerClass(request, client_address, self) # 这里
上一小节最后一个动作是 httpd.serve_forever
,调用的是 socketserver.BaseServer.serve_forever
方法。该方法采用了 selector 网络模型进行等待数据,每 0.5 秒遍历一次文件描述符,当有数据进来时,ready 变量会是一个 socket 请求对象,这时会将后续工作转交给 self._handler_request_noblock
方法 (即:socketserver.BaseServer._handler_request_noblock
) 去处理。
socketserver.BaseServer._handler_request_noblock
方法基本没做什么事情 (self.verify_request 压根就没有检查任何东西),直接就把后续工作转交给 socketserver.BaseServer.process_request
方法。
socketserver.BaseServer.process_request
也没做什么事情,直接就将后续工作转交给 socketserver.BaseServer.finish_request
方法,只不过在最后加了一条关闭请求的命令。
socketserver.BaseServer.finish_request
也没做什么事情,直接就将后续工作转交给 socketserver.BaseServer.RequestHandlerClass
。
socketserver.BaseServer.RequestHandlerClass
是由上一节 httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
传递过来的参数 django.core.servers.basehttp.WSGIRequestHandler
。 也就是说当执行 self.RequestHandler(request, client_address, self)
时等同于执行 django.core.servers.basehttp.WSGIRequestHandler(request, client_address, self)
。
小结
serve_forever 开启了一个 while 来无限监听网络层的 scoket 请求,当一条请求过来时,就层层转交到 django.core.servers.basehttp.WSGIRequestHandler
手中。
django.core.servers.basehttp.py 单独列出 WSGIRequestHandler 代码片段
class WSGIRequestHandler(simple_server.WSGIRequestHandler, object):
def address_string(self):
return self.client_address[0]
def get_environ(self):
for k, v in self.headers.items():
if ''_'' in k:
del self.headers[k]
env = super(WSGIRequestHandler, self).get_environ()
path = self.path
if ''?'' in path:
path = path.partition(''?'')[0]
path = uri_to_iri(path).encode(UTF_8)
env[''PATH_INFO''] = path.decode(ISO_8859_1) if six.PY3 else path
return env
def handle(self):
self.raw_requestline = self.rfile.readline(65537)
if len(self.raw_requestline) > 65536:
self.requestline = ''''
self.request_version = ''''
self.command = ''''
self.send_error(414)
return
if not self.parse_request(): # An error code has been sent, just exit
return
handler = ServerHandler(
self.rfile, self.wfile, self.get_stderr(), self.get_environ()
)
handler.request_handler = self # backpointer for logging
handler.run(self.server.get_app())
接着上一节继续分析:socketserver.BaseServer.RequestHandler(request, client_address, self)
等同于 django.core.servers.basehttp.WSGIRequestHandler(request, client_address, self)
。
首先 django.core.servers.basehttp.WSGIRequestHandler
的继承分布:
django.core.servers.basehttp.WSGIRequestHandler
wsgiref.simple_server.WSGIRequestHandler
http.server.BaseHTTPRequestHandler
socketserver.StreamRequestHandler
socketserver.BaseRequestHandler
object
从代码上看 django.core.servers.basehttp.WSGIRequestHandler
并没有 init 或者 call 方法,因此需要遍历所有父类对象。
最终在 socketserver.BaseRequestHandler 中看到了 init 实例初始化方法,它调用了 self.handle 方法 (即回调了:django.core.servers.basehttp.WSGIRequestHandler.handle
)。
handler = ServerHandler(self.rfile, self.wfile, self.get_stderr(), self.get_environ())
实例化了 ServerHandler 对象。
handler.run(self.server.get_app())
,意思是将 django.contrib.staticfiles.handlers.StaticFilesHandler
转交给 ServerHandler 去运行。
ServerHandler
对象并没有 run 方法,它的继承分布:
django.core.servers.basehttp.ServerHandler
wsgiref.simple_server.ServerHandler
wsgiref.handlers.SimpleHandler
wsgiref.handlers.BaseHandler
object
最终在 wsgiref.handlers.BaseHandler
中找到了 run 方法。
wsgiref.handlers.py
class BaseHandler:
def run(self, application):
...
self.result = application(self.environ, self.start_response) # 这里
self.finish_response()
application(self.environ, self.start_response)
也就相当于是 django.contrib.staticfiles.handlers.StaticFilesHandler.__call__(self.environ, lf.start_response)
。
django.contrib.staticfiles.handlers.py
class StaticFilesHandler(WSGIHandler):
def __call__(self, environ, start_response):
if not self._should_handle(get_path_info(environ)):
return self.application(environ, start_response)
return super(StaticFilesHandler, self).__call__(environ, start_response)
通过层层流转,最终进入 django 的静态文件处理的 Handler。
总结environ
这个变量在 django 的 WSGIServer 和 WSGIRequestHandler 中扮演这非常重要的角色,因为所有的客户端ip
、请求的URL
、cookie
、session
、header
等等信息都保存在其中。
WSGIServer: 用于处理 socket 请求和对接 WSGIRequestHandler。
WSGIRequestHandler:针对 environ
进行预处理和对接 WSGIServerHandler。
ServerHandler: 用于执行应用程序 (application) 和返回响应给 WSGIServer。
关于oracle 服务启动,关闭脚本(windows系统下)和oracle服务关闭命令的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于Android 源码 图形系统之 SurfaceFlinger 服务启动、Apache开启gzip压缩功能(windows系统下)、Centos 命令行 配置 服务启动 ntsysv、django 源码分析 --01 服务启动 (wsgi)的相关信息,请在本站寻找。
本文标签: