Apache中的挂钩剖析(3)

2023-10-26

5.5.7 可选挂钩
与标准挂钩相比,可选挂钩基本上没有太大的差异,唯一的区别就在于可选挂钩不一定需要被实现——这看起来令人迷惑的。不过你很快就会明白了。考虑一下,如果某个挂钩Hook_A是声明在一个可选模块中,那么正常情况下该模块没有被加载。如此此时某个模块想使用挂钩Hook_A,那么会发生什么情况呢。对于标准模块,Apache可能根本就无法进行编译。而可选挂钩则可以解决这种问题。对于可选挂钩,即使它没有被导入并运行,其余的模块也可以使用它。
可选挂钩的声明方法与标准挂钩声明没有任何区别,都是通过AP_DECLARE_HOOK进行的,比如下面的语句声明一个可选挂钩:
AP_DECLARE_HOOK(int , optional_hook , (request_rec *r , int n))
与标准挂钩相比,可选挂钩没有内部私有的数据结构。在标准挂钩中,为了保存各个模块对声明的挂钩的使用情况,通过声明AP_HOOK_STRUCT结构来实现。这种做法实际上是由挂钩实现者自行进行维护;而对于可选挂钩,模块编写者可以不需要维护该AP_HOOK_STRUCT结构了,该结构则转交内核维护。
在实现上,可选挂钩的声明从标准挂钩的AP_IMPLEMENT_HOOK_RUN_ALL形式转变为AP_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL
5.5.7.1可选挂钩数组
在Apache2.0中,任何模块对可选挂钩的调用信息都由Apache核心进行维护。在Apache内部,核心定义了两个全局哈希表s_phOptionalHooks和s_phOptionalFunctions分别保存所有的可选挂钩以及对应的挂钩处理句柄。S_phOptionalHooks哈希表中,可选挂钩名称用来作为哈希表Key键,而挂钩对应的挂钩数组则作为哈希表的Value值。其结构如上图所示。在Apr_hooks.c中,Apache提供了两个支持函数:apr_optional_hook_get和apr_optional_hook_add。

apr_optional_hook_get函数用来在哈希表s_phOptionalHooks中查找指定挂钩的挂钩数组,如果找到了则返回数组;否则返回NULL。
apr_optional_hook_add函数的原型声明如下:
APU_DECLARE(void) apr_optional_hook_add(const char *szName,void (*pfn)(void),
                    const char * const *aszPre,
                    const char * const *aszSucc,int nOrder)
该函数主要在可选挂钩szName数组中,增加一个登记项,登记的挂钩函数为pfn。同时aszPre、aszSucc以及nOrder与标准挂钩的含义相同。
在登记之前,函数必须能够在哈希表中找到挂钩szName对应的挂钩数组,这个可以通过apr_optional_hook_get来完成。由于可选挂钩可以没有任何挂钩函数,因此上图中挂钩数组为NULL也是可能的,此时必须为该挂钩首先生成挂钩数组,将该挂钩数组在哈希表中与键szName关联起来,同时进行排序。
如果szName挂钩数组已经存在,则直接调用apr_array_push相关信息压入数组并赋值。
可选挂钩数组中每个元素的结构都是apr_LINK__optional_t类型,其是宏APR_DECLARE_EXTERNAL_HOOK展开的结果,apr_LINK__optional_t结构实际如下所示:
typedef struct ap_LINK_optional_t
    {
         ap_HOOK_optional_t *pFunc;
         const char *szName;
         const char * const *aszPredecessors;
         const char * const *aszSuccessors;
         int nOrder;
    } ap_LINK_optional_t;
 
5.5.7.2 声明可选挂钩(APR_OPTIONAL_HOOK)
对于标准挂钩,注册使用挂钩通常使用ap_hook_name之类的函数,这些函数最终将使用信息登记到挂钩数组中去。而对于可选挂钩,由于不存在AP_HOOK_STRUCT宏,因此也就不存在挂钩数组了。在前面我们提到过,可选挂钩的保存是由Apache内核维护的,我们展开宏APR_OPTIONAL_HOOK就知道了。
APR_OPTIONAL_HOOK宏定义在ap_optional_hooks.h中:
#define APR_OPTIONAL_HOOK(ns,name,pfn,aszPre,aszSucc,nOrder) do { /
 ns##_HOOK_##name##_t *apu__hook = pfn; /
 apr_optional_hook_add(#name,(void (*)(void))apu__hook,aszPre, aszSucc, nOrder); /
} while (0)
 
5.5.7.3 APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL
对于标准挂钩,其实现分为VOID、FIRST和ALL三种,而对于可选挂钩,实现则归结只有一种ALL类型,即APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL,该宏定义如下:
#define APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ns,link,ret,name,args_decl,args_use,ok,decline) /
link##_DECLARE(ret) ns##_run_##name args_decl /
    { /
    ns##_LINK_##name##_t *pHook; /
    int n; /
    ret rv; /
    apr_array_header_t *pHookArray=apr_optional_hook_get(#name); /
    if(!pHookArray) /
     return ok; /
    pHook=(ns##_LINK_##name##_t *)pHookArray->elts; /
    for(n=0 ; n < pHookArray->nelts ; ++n) /
     { /
     rv=(pHook[n].pFunc)args_use; /
/
     if(rv != ok && rv != decline) /
         return rv; /
     } /
    return ok; /
    }
在status模块mod_status.c中我们声明的挂钩status_hook就是一个可选挂钩,该挂钩实现如下:
APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ap, STATUS, int, status_hook,
                                    (request_rec *r, int flags),
                                    (r, flags),
                                    OK, DECLINED)
     该宏展开后即实现了ap_run_status_hook函数,其实现过程,即展开结果如下所示:
     AP_DECLARE(int) ap_run_status_hook(request_rec* r,int flags)
     {
         ap_LINK_status_hook_t *pHook;
         int n;
         int rv;
    apr_array_header_t *pHookArray=apr_optional_hook_get(status_name);
    if(!pHookArray)
return ok;
    pHook=(ap_LINK_status_hook_t *)pHookArray->elts;
    for(n=0 ; n < pHookArray->nelts ; ++n)
{
rv=(pHook[n].pFunc)(r,flags);
if(rv != ok && rv != decline)
    return rv;
}
    return ok;
     }
5.5.8 可选函数
与挂钩存在类似的问题,函数也可能存在可选挂钩的问题。如果Apache在调用某一个函数的时候,该函数尚未被加载,会发生什么呢。你可能觉得DSO是个好的解决方法。如果指定的函数没有,则动态加载DSO模块进行查找。不过这种策略并不但是最完美的方案。首先,不是所有的平台都支持DSO;另一方面,
可选函数的特点正如其名,这就决定了它相对于Apache的动态性。正常的函数都是编写之后才会加入Apache中进行编译,而且一旦编译就无法更改。而可选函数则是在需要的时候动态产生的。在产生之前,没有人为之进行过专门的编写,因此链接代码中自然也就找不到该函数的实现。
可选函数的使用可以分为五大步骤:声明、实现、注册、获取以及函数调用。
5.5.8.1.可选函数的声明
声明一个可选函数通过宏APR_DECLARE_OPTIONAL_FN来实现,比如我们如果想声明一个optional_fun可选函数,其返回int类型,参数需要字符串类型,那么声明可以如下:
APR_DECLARE_OPTIONAL_FN(int,optional_fun,(const char* params))
APR_DECLARE_OPTIONAL_FN宏定义如下:
 #define APR_DECLARE_OPTIONAL_FN(ret,name,args) /
typedef ret (APR_OPTIONAL_FN_TYPE(name)) args
如果将上面的宏展开,则可以看出,该宏只是声明了一个apr_OFN_optional_fun_t类型的函数指针:
typedef int (apr_OFN_optional_fun_t)(const char* params)
一旦声明完毕,我们则将其进行实现如下,在实现中必须注意名称以及函数参数类型的匹配:
int optional_fun(const char* params)
{
       ……
       return 0;
}
5.5.8.2.可选函数的注册
可选函数由Apache核心统一维护。与可选挂钩类似,Apache核心维护了一个全局的哈希表s_phOptionalFunctions,该哈希表的键为可选函数的名称,而值则是对应的函数指针。为了便于Apache使用,我们必须在s_phOptionalFunctions中登记可选函数。函数的注册通过APR_REGISTER_OPTIONAL_FN进行,APR_REGISTER_OPTIONAL_FN定义如下:
#define APR_REGISTER_OPTIONAL_FN(name) do { /
 APR_OPTIONAL_FN_TYPE(name) *apu__opt = name; /
 apr_dynamic_fn_register(#name,(apr_opt_fn_t *)apu__opt); /
} while(0)
该宏内部实际调用了函数apr_dynamic_fn_register进行实际的注册。事实上,Apache中提供了相关函数来支持对s_phOptionalFunctions的操作,除了apr_dynamic_fn_register之外,还包括apr_register_optional_fnapr_dynamic_fn_retrieveapr_retrieve_optional_fn。不过其中apr_retrieve_optional_fnapr_register_optional_fnApache2.0中已经被废弃,因此不再多说。
apr_dynamic_fn_register的原型如下:
APU_DECLARE_NONSTD(void) apr_dynamic_fn_register(const char *szName,
                                                  apr_opt_fn_t *pfn)
参数szName是可选函数的名称,pfn则是实际可选函数的指针。如果s_phOptionalFunctions哈希表存在,函数只是简单的调用apr_hash_set将记录插入表中。
apr_dynamic_fn_retrieve函数原型为
APU_DECLARE(apr_opt_fn_t *) apr_dynamic_fn_retrieve(const char *szName)
该函数根据给定的函数名称获取实际的函数指针。
事实上,这两个函数都不允许直接调用,它们作为Apache的内部函数而存在,对外提供的则是宏APR_REGISTER_OPTIONAL_FNAPR_RETRIEVE_OPTIONAL_FN
对于optional_fun可选函数,注册语句如下:
APR_REGISTER_OPTIONAL_FN(optional_fun);
当用户想使用可选函数的时候,首先必须获得其函数指针,用法如下:
APR_OPTIONAL_FN_TYPE(some_fn) *pfn;
pfn=APR_RETRIEVE_OPTIONAL_FN(some_fn);
 
 
5.5.8.3.可选函数的使用
 
5.5.9智能挂钩
5.5.10挂钩工作机制
在前面的部分,我们对挂钩进行了详细的分析,但是还缺乏一个整体上的概念。从整体上来看挂钩的工作机制可以用下图来描述:

一个模块从挂钩的角度来看,其最重要的无非是两个方面:挂钩注册函数和挂钩处理函数。挂钩注册函数通常是模块结构中的register_hooks函数指针,该函数指针将调用实际的挂钩注册函数进行挂钩注册。挂钩注册的过程很简单,通过宏ap_hook_xxx实现。比如上图中声明了两个挂钩abc和xyz。
与此同时,模块中也将声明与挂钩对应的挂钩函数,该挂钩被触发的时候,该函数将被调用。正如前面描述,可以使用宏ap_run_xxx触发指定的挂钩。不过挂钩的触发通常是由核心模块在对客户端请求进行处理的过程中进行。
我们来看一个具体的例子,这是核心模块中关于挂钩的部分。
从模块的结构中可以看出,模块结构中包含一个指针register_hook,该指针通常指向模块中的实际的挂钩注册函数,比如,对于核心模块而言,其挂钩注册函数register_hooks,那么结构中的该指针也为register_hooks:
AP_DECLARE_DATA module core_module = {
    STANDARD20_MODULE_STUFF,
    create_core_dir_config,       /* create per-directory config structure */
    merge_core_dir_configs,       /* merge per-directory config structures */
    create_core_server_config,    /* create per-server config structure */
    merge_core_server_configs,    /* merge per-server config structures */
    core_cmds,                    /* command apr_table_t */
    register_hooks                /* register hooks */
};
而具体的register_hooks函数则如下:
static void register_hooks(apr_pool_t *p)
{
    ap_hook_create_connection(core_create_conn, NULL, NULL,
                              APR_HOOK_REALLY_LAST);
    ap_hook_pre_connection(core_pre_connection, NULL, NULL,
                           APR_HOOK_REALLY_LAST);
 
    ap_hook_post_config(core_post_config,NULL,NULL,APR_HOOK_REALLY_FIRST);
    ap_hook_translate_name(ap_core_translate,NULL,NULL,APR_HOOK_REALLY_LAST);
    ap_hook_map_to_storage(core_map_to_storage,NULL,NULL,APR_HOOK_REALLY_LAST);
    ap_hook_open_logs(ap_open_logs,NULL,NULL,APR_HOOK_REALLY_FIRST);
    ap_hook_handler(default_handler,NULL,NULL,APR_HOOK_REALLY_LAST);
    ap_hook_type_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST);
    ap_hook_fixups(core_override_type,NULL,NULL,APR_HOOK_REALLY_FIRST);
    ap_hook_access_checker(do_nothing,NULL,NULL,APR_HOOK_REALLY_LAST);
    ap_hook_create_request(core_create_req, NULL, NULL, APR_HOOK_MIDDLE);
    APR_OPTIONAL_HOOK(proxy, create_req, core_create_proxy_req, NULL, NULL,
                      APR_HOOK_MIDDLE);
    ap_hook_pre_mpm(ap_create_scoreboard, NULL, NULL, APR_HOOK_MIDDLE);
……
}
该函数的任务非常的简单,即声明该模块需要实现的挂钩,以及对应的处理函数,供主程序调用。

关于作者
张中庆,目前主要的研究方向是嵌入式浏览器,移动中间件以及大规模服务器设计。目前正在进行Apache的源代码分析,计划出版《Apache源代码全景分析》上下册。Apache系列文章为本书的草案部分,对Apache感兴趣的朋友可以通过flydish1234 at sina.com.cn与之联系!

如果你觉得本文不错,请点击文后的“推荐本文”链接!!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Apache中的挂钩剖析(3) 的相关文章

  • 使用 rpy2 将 NULL 从 Python 转换为 R

    在 R 中经常NULL值用作默认值 使用 Python 和 RPy2 如何显式提供NULL争论 None不可兑换 NotImplementedError 字符串 NULL 只会被转换为字符串 并在执行过程中导致错误 采取以下示例 使用tsi
  • 在 PHP 中,如何检测由于超出 max_input_vars 而导致输入变量被截断?

    我知道一个E WARNING由 PHP 生成 PHP 警告 未知 输入变量超过 1000 https stackoverflow com q 9673895 367456 但我如何在我的脚本中检测到这一点 一个 足够接近 的方法是检查if
  • 是否有 Subversion Checkout Hook 或类似的东西?

    我正在使用 subversion 存储库 并且我想知道何时有人要求我的存储库签出 就像 svn co 或 svn up 每当有人从我的 svn 服务器请求信息时 是否可以使用挂钩或其他方法来运行脚本或发送电子邮件 如何在不依赖 apache
  • .htaccess 在本地主机上给出 500 错误

    我是 MVC 框架的初学者 我正在尝试根据教程创建一个自己的 他们提供的 htaccess 文件包含 RewriteEngine On RewriteCond REQUEST FILENAME d RewriteCond REQUEST F
  • php7ts.dll 无法加载到服务器

    今天我已经安装了php7 但是当我重新启动apache时 它无法启动 尽管我再次编辑了httpd xampp conf文件到配置php7 无论如何我去了C xampp并运行apache start bat 然后我看到以下错误 Apache
  • 如何禁用在 Apache 中向目录名添加尾部斜杠的 301 重定向

    Apache 2 2 20 自动将所有指向目录且没有尾部斜杠的请求重定向到带有尾部斜杠的相同 URL 如下所示 GET some path to dir HTTP 1 1 Host www some org 301 Moved perman
  • IfModule:什么时候需要指定它?

    您是否需要将重写规则包含在以下内容中
  • 无法在 Netbeans 9 中设置 apache tomcat

    我正在尝试在 Netbeans IDE 9 中设置 apache tomcat 我已尝试以下步骤 但无法设置 在 工具 gt 服务器 中 我单击 添加服务器 按钮 显示以下消息 因此 我尝试从 工具 gt 插件 安装插件 会显示一个对话框
  • 将 apache documentRoot 设置为符号链接(以便于部署)

    我们正在寻找一种将 Apache DocumentRoot 指向符号链接的方法 例如 文档根目录 var www html finalbuild Finalbuild 应该指向 home user build3 之类的文件夹 当我们将新构建
  • 使用 .htaccess 启用 PHP 短标签

    我在自己的 Centos 服务器上设置了 Apache 并具有多个虚拟 Web 服务器 并且我希望仅为位于以下位置的其中一个 Web 服务器启用 PHP 短标记 var www ostickets html 我可以通过添加成功启用短标签sh
  • 如何调试apache虚拟主机配置?

    我的 apache 虚拟主机配置再次出现问题 使用默认配置而不是我的特定配置 问题不在于配置错误 而在于如何解决它 有人有好的建议可以快速解决此类问题吗 更多信息 默认的conf文件是这样的 NameVirtualHost
  • 如果端口不是 80,.htaccess 重定向到错误页面

    我正在运行一个便携式服务器 http www server2go web de 通过 USB 棒 问题是我还在我的本地计算机上安装了 WAMP 并且 Apache 不知何故在 Windows 启动时启动 因为一些我现在不记得的随机原因并且无
  • 项目链接在 Wamp 服务器上不起作用

    我正在另一台计算机上安装 Wamp 服务器来运行中型数据库和 UI 我已成功阻止 IIS 并将服务器路由到 Localhost 8080 但是每当我尝试从 localhost 主页访问我的项目时 在 www 文件中 我被重定向到页面未找到错
  • Apache mod_rewrite 将子域重写到子文件夹(通过内部重定向)

    我正在尝试编写一组 mod rewrite 规则 允许我的用户利用单个文件夹在不同项目上进行开发 而不必为每个项目添加虚拟主机 我的想法是为每个需要此功能的用户 仅 3 4 个 设置一个 全局虚拟主机 该虚拟主机类似于 my domain
  • 如何在另一个应用程序中挂钩 api 调用

    我正在尝试挂钩另一个应用程序的 ExtTextOut 和 DrawTextExt GDI 方法调用 我知道我需要使用 GetProcAddress 来查找 gdi32 dll 中那些方法的地址 并用我的函数的地址覆盖我想要挂钩的进程中的地址
  • 如何将路径添加到 Apache PATH 变量?

    我在 apache2 的 custom conf 文件中设置了以下内容 SetEnv PATH PATH opt local lib mysql5 bin this is a test 但是它不起作用 当我打电话时 hey shell ex
  • 如何在不改变相对路径的情况下使用apache的mod_rewrite重写规则

    我在 htaccess 中有以下重写规则 RewriteRule groups groupdetail php gname 1 L NC 这需要类似 www example com groups groupname 的内容并调用 www e
  • PHP 编译器 openssl 错误

    在提问之前 我必须说我已经tried堆栈和其他地方的每个类似问题都失败了 我无法使用composer因为这个错误 requires ext openssl gt the requested PHP extension openssl is
  • XAMPP:连接到本地主机修复? [执着的]

    我刚刚在我的计算机上安装了 XAMPP Windows 1 8 2 端口 80 受到保护 Apache 使用时没有任何问题 也没有任何端口冲突 我总是打开 Xampp 并在控制面板中启动 Apache 和 MySQL 模块 两个模块都在运行
  • 使用 .htaccess 处理数千个重定向

    我正在进行网站检修 因此 我将几个页面转移到新的格式 他们没有保留与以前相同的文件名 因此迁移有点棘手 Example news alpinezone com 93467 正在成为http alpinezone com still more

随机推荐

  • web前端入门到实战:CSS3 filter(滤镜)属性

    css3的滤镜filter属性 可以对网页中的图片进行类似Photoshop图片处理的效果 例如背景的毛玻璃效果 老照片 黑白照片 火焰效果等 一 blur px 高斯模糊 二 brightness 亮度 三 contrast 对比度 四
  • 通过Visio软件的宏编写Java代码

    1 新建Visio文件并打开 2 在 开发工具 选项卡上 单击 录制宏 3 操作Visio 如画图 画线等 4 点击停止录制 5 点击宏 6 可以查看到VB窗口的代码 可以一步步调试 根据宏代码尝试编写Java代码 一般情况下 宏中使用的代
  • 阿里面试题:为什么Map桶中个数超过8才转为红黑树

    这是一个好友面试阿里时 被问到的一个问题 应该不少人看到这个问题都会一面懵逼 因为 大部分的文章都是分析链表是怎么转换成红黑树的 但是并没有说明为什么当链表长度为8的时候才做转换动作 第一反应也是一样 只能初略的猜测是因为时间和空间的权衡
  • CloudQuery:更好地管理你的 OceanBase 数据库

    前言 作为 OceanBase 的生态合作伙伴 CloudQuery 简称 CQ 最新发布的社区版 2 2 0 新增了 OceanBase 数据库 为企业使用 OceanBase 数据库提供全面的支持 包括连接与认证 查询与分析 数据安全与
  • 软件测试开发和软件测试有什么区别?

    软件测试 软件测试是在测试中识别软件产品和 服务的准确性和质量的过程 显然 它的诞生是为了验证产品是否满足客户的特定先决条件和需求 在一天的工作结束前 确定特定的较终目标并测试执行一个框架或应用程序 以指出其错误 或缺陷 测试的职责是找到b
  • 颜色值透明度的百分数对应十六进制表

    目录 颜色简介 1 透明度的计算 2 透明度和不透明度的转换 3 透明度对应的十六进制值 4 不透明度对应的十六进制值 颜色简介 Android中的颜色值通常遵循RGB ARGB标准 使用时通常以 字符开头 以16进制表示 常用的颜色值格式
  • UDP协议详解

    文章目录 UDP概述 UDP主要特点 TCP和UDP区别 应用 适用场合 实际应用 代码演示 总结 UDP概述 UDP 是User Datagram Protocol的简称 中文名是用户数据报协议 是OSI Open System Inte
  • windows11文件夹共享设置 如何共享 如何访问

    一 确保文件夹共享相关服务处于启动状态 按快捷键Windows R 输入services msc 回车打开服务 确保以下服务都开启 需要全部开启后才能保证共享正常 1 DNS Client DNS 客户端服务 dnscache 缓存域名系统
  • 使用pip install -r requirements安装库出现的问题

    1 问题描述 ERROR No matching distribution found for matplotlib gt 3 2 2 WARNING There was an error checking the latest versi
  • redis五大数据类型+redis6 新类型(详解+指令)

    redis有五大数据类型分别是 1 String 字符串 2 List 列表 3 Set 集合 4 Hash 哈希 5 Zset 有序集合sorted set redis6 三种新数据类型 1 Bitmaps 实现对位的操作 以位为单位的数
  • SpringBoot配置postgre多数据源(亲测有效!!!)

    参考 https blog csdn net weixin 43240792 article details 106571925 稍微有一些不一样 pom引用
  • 蓝桥杯 试题 算法训练 最小距离 ( C++ )

    最小距离 最小距离 算法题目 算法代码 算法的核心思路 最小距离 算法题目 资源限制 时间限制 1 0s 内存限制 256 0MB 最小距离 问题描述 数轴上有n个数字 求最近的两个数 即min abs x y 输入格式 第一行包含一个整数
  • sEMG项目总结(3)STM32采集肌电信号

    STM32采集肌电信号 目录 STM32采集肌电信号 目录 1采集方式ADCTimerDMA 2采集程序的配置 3对采集的sEMG的分析 4STM32F407源码 1采集方式ADC Timer DMA 1 肌电信号采集板有双通道 信号的放大
  • Linux--文件、进程、fork、open、系统调用、库函数相关知识

    目录 1 进程打开文件的流程 2 先打开再fork的流程 重点 1 代码演示 2 分析 3 先fork再open 1 代码演示 2 分析 4 fork补充 5 系统调用与库函数的区别 1 进程打开文件的流程 inode 节点 存放有关文件的
  • Vlc.DotNet 视频画面拉伸满整个控件的方法

    Vlc DotNet 视频画面拉伸满整个控件的方法 引用Vlc DotNet 实现代码 实现思路 方案对比 踩坑记录 引用Vlc DotNet 根据官方的例子 首先下载VLC 把VLC里面的各种dll拷贝到输出目录里面 然后安装Nuget包
  • 如何使用python中读取csv数据文件?读取csv文件的几种方法

    1 第一种方法 使用csv库 打开csv文件 然后逐行读取文件内容 import csv filename abc csv with open filename as f reader csv reader f header row nex
  • 常用命令

    激活虚拟环境 source bin activate source bashrc source activate py36 source env torch bin activate 查看GPU使用情况 nvidia smi MAC从服务器
  • 【3.2】Hadoop运行模式之(伪分布式运行模式)

    一 启动HDFS并运行MapReduce程序 配置集群 1 配置 hadoop env sh 2 配置 core site xml 3 配置 hdfs site xml 启动集群 1 格式化 NameNode 第一次启动时格式化 以后就不要
  • 希望余生尽早开始

    我爱你在暖和的天气感冒 我爱你用一小时来点菜 我爱你皱着眉头看我 好像我是疯子一样 我爱跟你分别后 仍然萦绕不散的余香 我想在睡前和你聊天 我来这并不是因为我寂寞 也不是因为今天是除夕 是因为发现 如果你想要与某人共度余生 那你就会希望余生
  • Apache中的挂钩剖析(3)

    5 5 7 可选挂钩 与标准挂钩相比 可选挂钩基本上没有太大的差异 唯一的区别就在于可选挂钩不一定需要被实现 这看起来令人迷惑的 不过你很快就会明白了 考虑一下 如果某个挂钩Hook A是声明在一个可选模块中 那么正常情况下该模块没有被加载