看来昨天的大雨给北京确实带来了重创,早上出门去海淀驾校,北清路辛庄桥路段直接就堵死了,结果好不容易慢慢走到红绿灯那,才发现前方正抽水,封路了。唉,晚上回到家,上微博发现此次因灾遇难者37人,愿逝者安息!什么时候政府才能拿我们纳税人的钱办点正事,别整天搞形象工程了,来北京那么多年了,每次大雨都没能引起重视,也别搞什么引咎辞职了,直接抓了判刑吧。唉,牢骚发的有点多了,还是继续我们的主题吧,继续跟大家分享mochiweb源码。

  在上一篇最后,我们提到mochiweb_http:start/1函数,其中就一行代码,如下:

start(Options) ->mochiweb_socket_server:start(parse_options(Options)).

  其中mochiweb_http:parse_options/1 函数我们在上一篇,已经详细分析了,这一篇,我们来看下函数 mochiweb_socket_server:start/1 代码如下:

start(Options) ->case lists:keytake(link, 1, Options) of{value, {_Key, false}, Options1} ->start_server(start, parse_options(Options1));_ ->%% TODO: https://github.com/mochi/mochiweb/issues/58%%   [X] Phase 1: Add new APIs (Sep 2011)%%   [_] Phase 2: Add deprecation warning%%   [_] Phase 3: Change default to {link, false} and ignore link%%   [_] Phase 4: Add deprecation warning for {link, _} option%%   [_] Phase 5: Remove support for {link, _} option
            start_link(Options)end.

  这里:

  < Options = [{loop,{mochiweb_http,loop,
                                  [#Fun<mochiweb_example_web.0.8815963>]}},
             {name,mochiweb_example_web},
             {ip,{0,0,0,0}},
             {port,8080}]

  首先,我们看下系统函数:lists:keytake/3,erlang doc地址:http://www.erlang.org/doc/man/lists.html#keytake-3,截图如下:

  中文注释版本,参考:erlang lists 系列函数功能与用法详解(共68个函数),截图如下:

  知道这个函数的作用,我们就能从上下文知道,如果Options列表中含有配置{link, false},则这里调用第一个分支:start_server(start, parse_options(Options1)),Options1为移除{link, false}选项后的Options列表,否则调用第二个分支:start_link(Options),函数代码如下:

start_link(Options) ->start_server(start_link, parse_options(Options)).

  现在我们来做个对比:

  如果Options列表中含有配置{link, false},则调用:start_server(start, parse_options(Options1));

  如果Options列表中含有配置{link, true},或者不含有该配置(这里我们可以理解为默认配置),则调用:start_server(start_link, parse_options(Options));

  那么我们看下mochiweb_socket_server:start_server/2函数的具体实现:

start_server(F, State=#mochiweb_socket_server{ssl=Ssl, name=Name}) ->ok = prep_ssl(Ssl),case Name ofundefined ->gen_server:F(?MODULE, State, []);_ ->gen_server:F(Name, ?MODULE, State, [])end.

  这里F的值为start或start_link,现在大家对Options列表中是否含有link,且值是否为true是否有进一步的理解。其实这里很简单,该选项决定了以什么方式调用gen_server,如果你现在还对gen_server一无所知,建议你移步这里Gen_Server行为,希望你看完这个能对gen_server有所了解,这里也同时推荐《Erlang/OTP并发编程实战》这本书,目前我还没有看完,刚看到第二章,收获还是不少的。

  好了,有个函数差点漏了,我们看下 mochiweb_socket_server:parse_options/1 这个函数,完整代码如下:

parse_options(State=#mochiweb_socket_server{}) ->State;
parse_options(Options) ->parse_options(Options, #mochiweb_socket_server{}).

  这里,如果配置为记录mochiweb_socket_server,则调用第一个分支,返回该配置。否则调用第二个分支,调用函数mochiweb_socket_server:parse_options/2传递Options为第一个参数,#mochiweb_socket_server{}记录为第二个参数,这个记录定义如下:

-record(mochiweb_socket_server,{port,loop,name=undefined,%% NOTE: This is currently ignored.max=2048,ip=any,listen=null,nodelay=false,backlog=128,active_sockets=0,acceptor_pool_size=16,ssl=false,ssl_opts=[{ssl_imp, new}],acceptor_pool=sets:new(),profile_fun=undefined}).

  函数:mochiweb_socket_server:parse_options/2 完整代码如下:

parse_options([], State) ->State;
parse_options([{name, L} | Rest], State) when is_list(L) ->Name = {local, list_to_atom(L)},parse_options(Rest, State#mochiweb_socket_server{name=Name});
parse_options([{name, A} | Rest], State) when A =:= undefined ->parse_options(Rest, State#mochiweb_socket_server{name=A});
parse_options([{name, A} | Rest], State) when is_atom(A) ->Name = {local, A},parse_options(Rest, State#mochiweb_socket_server{name=Name});
parse_options([{name, Name} | Rest], State) ->parse_options(Rest, State#mochiweb_socket_server{name=Name});
parse_options([{port, L} | Rest], State) when is_list(L) ->Port = list_to_integer(L),parse_options(Rest, State#mochiweb_socket_server{port=Port});
parse_options([{port, Port} | Rest], State) ->parse_options(Rest, State#mochiweb_socket_server{port=Port});
parse_options([{ip, Ip} | Rest], State) ->ParsedIp = case Ip ofany ->any;Ip when is_tuple(Ip) ->Ip;Ip when is_list(Ip) ->{ok, IpTuple} = inet_parse:address(Ip),IpTupleend,parse_options(Rest, State#mochiweb_socket_server{ip=ParsedIp});
parse_options([{loop, Loop} | Rest], State) ->parse_options(Rest, State#mochiweb_socket_server{loop=Loop});
parse_options([{backlog, Backlog} | Rest], State) ->parse_options(Rest, State#mochiweb_socket_server{backlog=Backlog});
parse_options([{nodelay, NoDelay} | Rest], State) ->parse_options(Rest, State#mochiweb_socket_server{nodelay=NoDelay});
parse_options([{acceptor_pool_size, Max} | Rest], State) ->MaxInt = ensure_int(Max),parse_options(Rest,State#mochiweb_socket_server{acceptor_pool_size=MaxInt});
parse_options([{max, Max} | Rest], State) ->error_logger:info_report([{warning, "TODO: max is currently unsupported"},{max, Max}]),MaxInt = ensure_int(Max),parse_options(Rest, State#mochiweb_socket_server{max=MaxInt});
parse_options([{ssl, Ssl} | Rest], State) when is_boolean(Ssl) ->parse_options(Rest, State#mochiweb_socket_server{ssl=Ssl});
parse_options([{ssl_opts, SslOpts} | Rest], State) when is_list(SslOpts) ->SslOpts1 = [{ssl_imp, new} | proplists:delete(ssl_imp, SslOpts)],parse_options(Rest, State#mochiweb_socket_server{ssl_opts=SslOpts1});
parse_options([{profile_fun, ProfileFun} | Rest], State) when is_function(ProfileFun) ->parse_options(Rest, State#mochiweb_socket_server{profile_fun=ProfileFun}).

  从具体的函数逻辑来看,其实这个函数也很简单,就是分别去匹配Options中的每个配置项,然后按照一定格式去存储到记录#mochiweb_socket_server{}中,详细的逻辑我就不一行行跟大家分析了。如果这里你遇到什么地方不理解,欢迎大家留言跟我交流。

  我们回到mochiweb_socket_server:start_server/2函数详细分析下:

start_server(F, State=#mochiweb_socket_server{ssl=Ssl, name=Name}) ->ok = prep_ssl(Ssl),case Name ofundefined ->gen_server:F(?MODULE, State, []);_ ->gen_server:F(Name, ?MODULE, State, [])end.

  第一行,调用函数:mochiweb_socket_server:prep_ssl/1,完整代码如下:

prep_ssl(true) ->ok = mochiweb:ensure_started(crypto),ok = mochiweb:ensure_started(public_key),ok = mochiweb:ensure_started(ssl);
prep_ssl(false) ->ok.

  这里仅仅是判断配置项中是否使用SSL协议,关于这个协议,参考维基百科:安全套接层Secure Sockets Layer,SSL),如果使用ssl,则对应启动这三个应用。

  第二行,判断配置项中是否存在name定义,如果存则,则使用该名字作为gen_server的名称,否则不使用名称注册该gen_server。

  当启动这个gen_server,最后会调用:mochiweb_socket_server:init/1函数,完整代码如下:

init(State=#mochiweb_socket_server{ip=Ip, port=Port, backlog=Backlog, nodelay=NoDelay}) ->process_flag(trap_exit, true),BaseOpts = [binary,{reuseaddr, true},{packet, 0},{backlog, Backlog},{recbuf, ?RECBUF_SIZE},{active, false},{nodelay, NoDelay}],Opts = case Ip ofany ->case ipv6_supported() of % IPv4, and IPv6 if supportedtrue -> [inet, inet6 | BaseOpts];_ -> BaseOptsend;{_, _, _, _} -> % IPv4[inet, {ip, Ip} | BaseOpts];{_, _, _, _, _, _, _, _} -> % IPv6[inet6, {ip, Ip} | BaseOpts]end,listen(Port, Opts, State).

  好了,这一篇就到这里,谢谢大家的耐心阅读,下一篇,我们就从这个函数继续和大家分享mochiweb源码。

  明天还要继续练车,大家早点休息,好梦。

转载于:https://www.cnblogs.com/yourihua/archive/2012/07/23/2604264.html

mochiweb 源码阅读(八)相关推荐

  1. mybatis源码阅读(八) ---Interceptor了解一下

    转载自  mybatis源码阅读(八) ---Interceptor了解一下 1 Intercetor MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用.默认情况下,MyBatis允许 ...

  2. 源码阅读:AFNetworking(八)——AFAutoPurgingImageCache

    该文章阅读的AFNetworking的版本为3.2.0. AFAutoPurgingImageCache该类是用来管理内存中图片的缓存. 1.接口文件 1.1.AFImageCache协议 这个协议定 ...

  3. Soul网关源码阅读(八)路由匹配初探

    Soul网关源码阅读(八)路由匹配初探 简介      今日看看路由的匹配相关代码,查看HTTP的DividePlugin匹配 示例运行      使用HTTP的示例,运行Soul-Admin,Sou ...

  4. 【vn.py学习笔记(八)】vn.py utility、BarGenerator、ArrayManager源码阅读

    [vn.py学习笔记(八)]vn.py utility.BarGenerator.ArrayManager源码阅读 写在前面 1 工具函数 2 BarGenerator 2.1 update_tick ...

  5. 源码阅读:AFNetworking(十六)——UIWebView+AFNetworking

    该文章阅读的AFNetworking的版本为3.2.0. 这个分类提供了对请求周期进行控制的方法,包括进度监控.成功和失败的回调. 1.接口文件 1.1.属性 /**网络会话管理者对象*/ @prop ...

  6. 源码阅读:SDWebImage(六)——SDWebImageCoderHelper

    该文章阅读的SDWebImage的版本为4.3.3. 这个类提供了四个方法,这四个方法可分为两类,一类是动图处理,一类是图像方向处理. 1.私有函数 先来看一下这个类里的两个函数 /**这个函数是计算 ...

  7. 源码阅读:SDWebImage(十九)——UIImage+ForceDecode/UIImage+GIF/UIImage+MultiFormat

    该文章阅读的SDWebImage的版本为4.3.3. 由于这几个分类都是UIImage的分类,并且内容相对较少,就写在一篇文章中. 1.UIImage+ForceDecode 这个分类为UIImage ...

  8. 超像素SLIC算法源码阅读

    超像素SLIC算法源码阅读 超像素SLIC算法源码阅读 SLIC简介 源码阅读 实验结果 其他超像素算法对比 超像素SLIC算法源码阅读 SLIC简介 SLIC的全称Simple Linear Ite ...

  9. TiDB 源码阅读系列文章(十六)INSERT 语句详解

    在之前的一篇文章 <TiDB 源码阅读系列文章(四)INSERT 语句概览> 中,我们已经介绍了 INSERT 语句的大体流程.为什么需要为 INSERT 单独再写一篇?因为在 TiDB ...

最新文章

  1. MyBatis常见面试题汇总
  2. js_jQuery综合机试练习题
  3. java 方法 示例_Java集合syncedSortedSet()方法与示例
  4. 数据结构探险系列—栈篇-学习笔记
  5. mongodb数据库的备份与恢复
  6. 性能测试小总结(四) 结果分析(未完成)
  7. 如何合理的配置线程数?
  8. RecyclerView(四)设置分割线样式(Android 5.0 新特性)
  9. Git部署远程仓库至github
  10. python中函数参数*args和**kw的区别
  11. etcd工作原理和部署指南
  12. 计算机输入输出接口是交接界面,计算机组成原理试题1
  13. 华为四核处理器K3V2
  14. 模块二、添加Customer 类
  15. Windows安全加固简介
  16. 可以同情弱者,别同情弱势!
  17. 英语——长难句分析及技巧
  18. 计算机网络发展的第四阶段特点,计算机网络基础考试重点.doc
  19. win7matlab2016启动闪退,大白菜修复win7系统启动matlab出现闪退的图文方案
  20. 进程管理API之find_get_pid

热门文章

  1. python【Multiprocessing and threading】深入浅出多进程和多线程
  2. 【Network Security!】服务器远程管理
  3. 基础算法 —— 贪心算法
  4. c++ 多重背包状态转移方程_背包问题之零钱兑换
  5. 网络推广外包浅析当下网站优化处于健康状态有利于网络推广外包
  6. java 重定向到某个页面并弹出消息_Java开发面试宝典之网络通信篇
  7. 芯片如何储存信息_机器视觉检测设备相机的分辨率是如何定义的怎么分类?
  8. mac r 导出csv文件_每天学习一点R:8.数据的导入和输出
  9. 开发日记-20190914 关键词 汇编语言王爽版 第四章
  10. 开发日记-20190821 关键词 读书笔记《掌控习惯》DAY 1