Gen_fsm行为实践与分析
1.简介
Gen_fsm是一个通用的有限状态机,它描述了这样的一组关系:State(S) x Event(E) -> Actions(A),State(S')这个关系意味着:如果在S状态下发生事件E,将执行动作A并返回状态S'.对于一个FSM实现可以使用gen_fsm行为来实现,它提供了标准的接口函数和回调函数。并且,gen_fsm进程可以安装在supervisor监控树中。回调函数与导出函数的关系如下:
gen_fsm moduleCallbackmodule
-----------------------------
gen_fsm:start_link ----->Module:init/1
gen_fsm:send_event ----->Module:StateName/2
gen_fsm:send_all_state_event ----->Module:handle_event/3
gen_fsm:sync_send_event ----->Module:StateName/3
gen_fsm:sync_send_all_state_event ----->Module:handle_sync_event/4
------>Module:handle_info/3
------>Module:terminate/3
------>Module:code_change/4如果回调函数失败或返回坏的值,gen_fsm将会终止。
gen_fsm处理系统消息记录记录在sys模块中(sys模块可以用来调试gen_fsm)。
注意:gen_fsm不会主动的捕获退出信号,必须在回调函数初始化时被指定。process_flag(trap_exit, true).
如果指定的gen_fsm不存在或给与的参数不正确,模块里的所有函数将失败。
如果回调函数返回'hibernate',gen_fsm进程将进入hibernate状态。如果服务器长时间处于空闲状态这可能非常有用。然而应该非常小心的使用这个特征,因为它意味着至少有垃圾回收器,当调用一个忙碌的状态机时,你不能做你想做的事情(会因为垃圾回收而导致状态机停滞)。
2.函数
2.1导出函数
start_link(Module, Args, Options) -> Result
start_link(FsmName, Module, Args, Options) -> Result
FsmName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}Options = [Option]
Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}
Dbgs = [Dbg]
Dbg = trace | log | statistics
| {log_to_file,FileName} | {install,{Func,FuncState}}
SOpts = [SOpt]
SOpt - see erlang:spawn_opt/2,3,4,5
Result = {ok,Pid} | ignore | {error,Error}
Error = {already_started,Pid} | term()
link
|{priority, priority_level()}
|{min_heap_size, integer()>=0}
|{min_bin_vheap_size, integer()>=0}
|{fullsweep_after, integer()>=0}
如果gen_fsm被成功的创建和初始化,将返回{ok,Pid},如果已经存在指定FsName的进程,将返回{error,{alredy_started, Pid}}.如果Module:init/1因为Reason失败,将返回{error,Reason}.如果Module:init/1返回{stop, Reason}或ignore,并且相应的返回{error,Reason}或ignore.
start(Module, Args, Options) -> Result
start(FsmName, Module, Args, Options) -> Result
FsmName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}Options = [Option]
Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}
Dbgs = [Dbg]
Dbg = trace | log | statistics
| {log_to_file,FileName} | {install,{Func,FuncState}}
SOpts = [term()]
Result = {ok,Pid} | ignore | {error,Error}
Error = {already_started,Pid} | term()
用于创建一个独立gen_fsm进程,并不是监控树的一部分。参数描述参见start_link/3,4.send_event(FsmRef, Event) -> ok
- Pid
- Name,本地注册的gen_fsm
- {Name,Node}另一个节点上本地注册gen_fsm
- {global,GlobalName}全局注册的gen_fsm
- {via,Module,ViaName}通过指定的进程注册的gen_fsm
send_all_state_event(FsmRef, Event) -> ok
FsmRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()
向gen_fsm的FsmRef发送一个异步事件并立即返回ok.这个gen_fsm将调用Module:handle_event/3来处理这个事件。参数描述参见send_event/2.send_event和send_all_state_event的不同是处理事件的回调函数不同,该函数是在任何状态下都以同样的方式处理事件,只有一个handle_event子句来处理事件。
sync_send_event(FsmRef, Event) -> Reply
sync_send_event(FsmRef, Event, Timeout) -> Reply
FsmRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()Timeout = int()>0 | infinity
Reply = term()
向gen_fsm的FsmRef发送一个事件然后等待直到reply返回或发生超时,将调用Module:StateName/3来处理事件,StateName是gen_fsm当前的状态名。
参数描述参见send_event/2.
Timeout是一个等待reply返回大于0指定的毫秒数,或指定为infnity.默认是5000毫秒。如果指定时间内未返回reply函数调用失败。
返回值Reply是回调函数Module:StateName/3返回的。
sync_send_all_state_event(FsmRef, Event) -> Reply
sync_send_all_state_event(FsmRef, Event, Timeout) -> Reply
FsmRef = Name | {Name,Node} | {global,GlobalName} | {via,Module,ViaName} | pid()Timeout = int()>0 | infinity
向gen_fsm的FsmRef发送一个事件然后等待reply的返回或超时。gen_fsm将调用Module:handle_sync_event/4来处理。
参数描述参见send_event/2和sync_send_event/3.
reply(Caller, Reply) -> true
Caller - see below该函数用于通过gen_fsm向指定的客户端发送返回值,例如sync_send_event/2,3或sync_send_all_state/2,3当其回调函数Module:StateName/3或Module:handle_sync_event/4不能返回值时。
Caller是客户端的From,Reply是一个任意的项式,他将返回给sync_send_event/2,3或sync_send_all_state/2,3.
send_event_after(Time, Event) -> Ref
Time = integer()Ref = reference()
用于在gen_fsm内部发送一个延迟事件,在Time时间后将触发。立即返回一个引用,它可以用cancel_timer/1来取消该延迟事件。
gen_fsm将调用Module:StateName/2处理该事件,StateName是当gen_fsm在延迟时间到时延迟事件被发送时的状态名字。
Event是任意类型的项式将作为参数传递给Module:StateName/2.
start_timer(Time, Msg) -> Ref
Time = integer()Ref = reference()
在gen_fsm内部发送一个超时的事件,在Time事件时执行,并立刻返回他的引用,可以通过cancel_timer/1来取消该方法。
gen_fsm将调用Module:StateName/2处理该事件,StateName是发送该超时事件的状态。
Msg是任意类型项式的超时信息{timeout, Ref, Msg},将作为Module:StateName/2的参数信息。
cancel_timer(Ref) -> RemainingTime | false
Ref = reference()RemainingTime = integer()
gen_fsm调用该函数来取消名称为Ref的内部定时器。
引用Ref是由send_event_after/2和start_timer/2返回。
如果定时器已经超时,但是并没用事件发送,他被作为超时事件被取消,因此该函数的返回不会有错误的计时器事件。
如果Ref指定的是活跃的事件计时器,将返回剩余的时间直到计时器终止前,否则返回false.
enter_loop(Module, Options, StateName, StateData)
enter_loop(Module, Options, StateName, StateData, FsmName)
enter_loop(Module, Options, StateName, StateData, Timeout)
enter_loop(Module, Options, StateName, StateData, FsmName, Timeout)
Options = [Option]Option = {debug,Dbgs}
Dbgs = [Dbg]
Dbg = trace | log | statistics
| {log_to_file,FileName} | {install,{Func,FuncState}}
FsmName = {local,Name} | {global,GlobalName} | {via,Module,ViaName}
Timeout = int() | infinity
使一个存在的进程变成gen_fsm.没有返回,取而代之的是,调用进程将进入gen_fsm的接受循环成为一个gen_fsm进程。进程必须使用proc_lib来启动该函数.因此通过该函数进行初始化和名字注册。
当要进行一个比gen_fsm更要复杂的初始化过程时,这个函数非常有用。
Module, Options and FsmName与start_link中的意义一样。然而,如果FsmName被指定,在这个函数调用前,这个进程必须被相应地注册。
StateName,StateDate and Timeout的意义与Module:init/1一样。同时,回调模块Module不需要导出init/1方法。
失败情况:通过proc_lib启动函数不能启动该进程时;不能注册指定的FsmName时。
2.2回调函数
Module:init(Args) -> Result
Result = {ok,StateName,StateData} | {ok,StateName,StateData,Timeout}| {ok,StateName,StateData,hibernate}
| {stop,Reason} | ignore
Timeout = int()>0 | infinity
每当gen_fsm使用gen_fsm:start[_link]/3,4开始时,通过新进程调用该函数来初始化。
Args是启动函数提供的参数。
如果初始化成功,这个函数应该返回{ok, StateName, SateData[,Timeout | hibernate]},SateName是初始的状态名,StateData是初始的状态数据。
如果提供了一个整数的超时值,在Timeout时间内如果没有接受到事件或消息那么超时将发生。超时的表现是通过一个原子timeout被回调函数Modules:StateName/2处理。其默认值是infinity,表示会一直等待下去。
如果hibernate被指定,那么进程将进入hibernate状态等待下一个消息的到达。
如果在初始化期间发生了一些错误,函数应该返回{stop, Reason}或ignore.
Module:StateName(Event, StateData) -> Result
Event = timeout | term()Result = {next_state,NextStateName,NewStateData}
| {next_state,NextStateName,NewStateData,Timeout}
| {next_state,NextStateName,NewStateData,hibernate}
| {stop,Reason,NewStateData}
Timeout = int()>0 | infinity
这是一个每个可能状态名的一个函数实例。每当gen_fsm接收到由gen_fsm:send_event/2发送过来的事件时,当前状态名StateName的函数实例将被调用来处理这个事件。同时他也处理超时事件。
Event要么是超时发生时的原子timeout,或send_event/2传递过来的。
如果该函数返回{next_state, NextStateName, NewStateData [, Timeout | hibernate]}时,gen_fsm将继续执行同时转变到新的状态NextStateName并更新数据NewStateDate.hibernate和Timeout的描述详见Module:init/1.
如果返回{stop, Reason, NewStateName},gen_fsm将调用Module:terminate(Reason, NewStateData)终止。
Module:handle_event(Event, StateName, StateData) -> Result
Result = {next_state,NextStateName,NewStateData}| {next_state,NextStateName,NewStateData,Timeout}
| {next_state,NextStateName,NewStateData,hibernate}
| {stop,Reason,NewStateData}
Timeout = int()>0 | infinity
每当gen_fsm接收到由gen_fsm:send_all_state_event/2发送过来的事件时,这个函数将被调用来处理该事件。
参数描述以及返回值描述参见Module:StateName/2.
Module:StateName(Event, From, StateData) -> ResultFrom = {pid(),Tag}Result = {reply,Reply,NextStateName,NewStateData}| {reply,Reply,NextStateName,NewStateData,Timeout}| {reply,Reply,NextStateName,NewStateData,hibernate}| {next_state,NextStateName,NewStateData}| {next_state,NextStateName,NewStateData,Timeout}| {next_state,NextStateName,NewStateData,hibernate}| {stop,Reason,Reply,NewStateData} | {stop,Reason,NewStateData}Timeout = int()>0 | infinityReason = normal | term()这是一个每个可能状态名的一个函数实例。每当gen_fsm接收到由gen_fsm:sync_send_event/2发送过来的事件时,当前状态名StateName的函数实例将被调用来处理这个事件。Event是由sync_send_event的Event参数提供。From是一个元组{Pid, Tag},Pid是调用sync_send_event/2,3的进程的Pid,Tag是他的唯一标识。当函数返回{reply, Reply, NextStateName, NewStateName [, Timeout | hibernate]}时,gen_fsm将继续执行同时转变到状态NextStateName,并跟新值到NewStateData.Timeout和hibernate的描述参见Module:init/1.当函数返回{next_state, NextStateName, NewStateData [, Timeout | hibernate]}时,gen_fsm将继续执行,同时转变到状态NextStateName并更数据到NewStateName.同时必须现实的调用gen_fsm:reply/2来返回数据reply给From.如果函数返回{stop, Reason, Reply, NewStateData}或{stop, Reason, NewStateNameData}(该情况必须明确的使用gen_fsm:reply/2返回reply)时,gen_fsm将调用Module:terminate(Reason NewStateName)终止。Module:handle_sync_event(Event, From, StateName, StateData) -> Result
Result = {reply,Reply,NextStateName,NewStateData}| {reply,Reply,NextStateName,NewStateData,Timeout}
| {reply,Reply,NextStateName,NewStateData,hibernate}
| {next_state,NextStateName,NewStateData}
| {next_state,NextStateName,NewStateData,Timeout}
| {next_state,NextStateName,NewStateData,hibernate}
| {stop,Reason,Reply,NewStateData} | {stop,Reason,NewStateData}
Timeout = int()>0 | infinity
每当gen_fsm接受到由gen_fsm:sync_send_all_state_event/2,3发送过来的事件时,这个函数被调用来处理该事件。
参数详见Module:StateName/3描述。
Module:handle_info(Info, StateName, StateData) -> Result
Result = {next_state,NextStateName,NewStateData}| {next_state,NextStateName,NewStateData,Timeout}
| {next_state,NextStateName,NewStateData,hibernate}
| {stop,Reason,NewStateData}
当gen_fsm接收到其他消息时(除出去同步或异步事件以及系统消息),该函数被调用来处理该消息。
其他参数以及返回值描述参见Module:StateName/2.
Module:terminate(Reason, StateName, StateData)
Reason = normal | shutdown | {shutdown,term()} | term()这个函数在gen_fsm终止时被调用。它的作用与Module:init/1相对并可以做一些必要的清理。当他返回gen_fsm因为Reason终止的原因,返回值将被忽略。
如果Reason是term指定的停止原因,StateName就是当前状态,StateData就是当前状态数据。
如果Reason取决于gen_fsm为什么被终止。如果他是因为另一个回调函数返回了stop元组{stop,...},Reason将在那个元组里被指定。如果由于失败导致,Reason是一个错误原因。
如果gen_fsm是监控树的一部分,被他的监控树所终止,Reason = shutdown 要满足以下条件:
- gen_fsm被设置成可捕获退出信号
- 监控树的关闭策略是指定Timeout而不是brutal_kill
甚至如果gen_fsm并不是监控树的一部分,如果从其父进程接收到'EXIT'信号这个函数也会被调用,Reason就是'EXIT'信息。否则,gen_fsm将立即终止。
注意:非normal, shutdown, or {shutdown,Term}的任何其他原因,如gen_fsm的终止是因为error,这些错误将由error_logger:format/2进行报告。
Module:code_change(OldVsn, StateName, StateData, Extra) -> {ok, NextStateName, NewStateData}
OldVsn = Vsn | {down, Vsn}关于代码的热更新,后续专题会继续介绍。
3.实践
3.1 启动一个gen_fsm
start_link(Code)->
%%gen_fsm:start_link({local,?SERVER},?MODULE, lists:reverse(Code),[]).
gen_fsm:start({local,?SERVER},?MODULE, lists:reverse(Code),[{timeout,1000}]).
-spec(init(Args:: term())->
{ok,StateName:: atom(),StateData::#state{}} |
{ok,StateName:: atom(),StateData::#state{}, timeout() | hibernate} |
{stop,Reason:: term()}| ignore).
init(Code)->
%%timer:sleep(2000),
%%{stop,Code}.
%%ignore.
{ok, unlock,{[],Code}}.当调用gen_fsm:start开启fsm服务器事,将回调Modules:init/1进行初始化,并初始化状态unlock,以及状态值{[],Code}.
3.2 发送一个事件
button(Digital)->
gen_fsm:send_event(?SERVER,{button,Digital}).
unlock({button,Digital},{SoFar,Code})->
case[Digital|SoFar] of
Code->
io:format("Pass OK!~n"),
do_unlock(),
{next_state, open,{[],Code},3000};
InCompletwhen length(InComplet)< length(Code)->
io:format("Input:~p,InComplet~p,Code:~p~n",[Digital,[Digital|SoFar],Code]),
{next_state, unlock,{InComplet,Code}};
_Worng->
io:format("ReInput Password!~n"),
{next_state, unlock,{[],Code}}
end.
open(timeout,State)->
do_lock(),
timer:sleep(1000),
%%{stop, normal,State}.
{next_state, unlock,State}.发送一个异步事件,然后当前状态对事件进行处理,根据一定的条件进行状态变更,返回{stop, Reason, State}将调用Module:terminate/2进行终止.
sync_button()->
gen_fsm:sync_send_event(?SERVER,open).
%%gen_fsm:sync_send_event(?SERVER,close,1000). unlock(open,_From,State)->
do_unlock(),
io:format("~p~p~n",[_From,State]),
gen_fsm:reply(_From,{ok,"Successfly!"}),
%%gen_fsm:reply(_From,normal),{stop, normal,State}.
%%{stop, normal, normal,State}.
{next_state, close,State,1000}.
%%Reply= ok,
%%{reply,Reply, open,State,3000}.
close(timeout ,State)->
do_lock(),
io:format("~p~p~n",["timeout",State]),
{next_state, open,State,1000}.发送一个同步事件,当前状态进行处理以后等待返回,返回{reply, Reply, StateName, State},Reply将返回给调用端。返回{next_state, State, State},那么必须在返回之前调用gen_fsm:reply/2显示的返回给调用端。
3.3 发送一个所有状态都能接受的事件
send(Data)->
gen_fsm:send_all_state_event(?SERVER,{send,Data}).
-spec(handle_event(Event:: term(),StateName:: atom(),
StateData::#state{}) ->
{next_state,NextStateName:: atom(),NewStateData::#state{}} |
{next_state,NextStateName:: atom(),NewStateData::#state{},
timeout()| hibernate}|
{stop,Reason:: term(),NewStateData::#state{}}).
handle_event({send,Data},StateName,State)->
io:format("Send Data:~p,StateName:~p,State,~p~n",[Data,StateName,State]),
{next_state,StateName,State}.向所有的状态发送一个异步的事件,并由handle_event/3进行处理。
sync_send(Data)->
Res= gen_fsm:sync_send_all_state_event(?SERVER,{send,Data}),
io:format("~p~n",[Res]).
handle_sync_event({send,Data},_From,StateName,State)->
timer:sleep(2000),
gen_fsm:reply(_From,{Data,StateName,State,_From}),
{next_state, open,State,1000}.
%%{reply,{Data,StateName,State,_From}, open,State,1000}.
%%{reply,{Data,StateName,State,_From},StateName,State}.向所有的状态发送一个同步事件,并由handle_sync_event/4进行处理,并向调用端返回Reply,如果返回{next_state, StateName, State}必须显示调用gen_fsm:reply/2向调用端返回。
3.4 开启一个定时器
unlock(open,_From,State)->
do_unlock(),
%%gen_fsm:send_event_after(2500,{button,48}),
Ref= gen_fsm:start_timer(1500,"start_timer"),
io:format("~p~p~n",[_From,State]),
gen_fsm:reply(_From,{ok,"Successfly!"}),
proc_lib:spawn(fun()->
timer:sleep(2000),
Time= gen_fsm:cancel_timer(Ref),
io:format("RemainTime:~p~n",[Time])
end),
%%gen_fsm:reply(_From,normal),{stop, normal,State}.
%%{stop, normal, normal,State}.
{next_state, close,State,1000}.
%%Reply= ok,
%%{reply,Reply, open,State,3000}.send_event_after/2表示在指定时间后发送事件,start_timer/2表示在指定事件后发送一个超时事件{timeout, Ref, Msg},但同时可以用cancel_timer/1来结束定时器。
3.5 将普通进程转变为gen_fsm进程
-spec(start_link()->{ok, pid()}| ignore |{error,Reason:: term()}).
start_link()->
io:format("start_link~n"),
proc_lib:start_link(?MODULE, start_loop,[self()]).
%%gen_fsm:start_link({local,?SERVER},?MODULE,[],[]).
start_loop(Person)->
io:format("start_loop~n"),
proc_lib:init_ack(Person,self()),
register(?MODULE,self()),
gen_fsm:enter_loop(?MODULE,[], state_name,#state{}, {local, ?MODULE}).通过gen_fsm:enter_loop将一个普通的进程转变为gen_fsm进程。同时不必导出Module:init/1回调函数。适用于比init:/1要更复杂的初始化的处理。
4.总结
gen_fsm实现了通用的有限状态机(FSM),对与在多种状态间的变更处理非常的有用,比如文本解析,模式匹配、游戏逻辑等等方面的处理都是它的强项,所以这个behaviour非常之重要,gen_fsm提供了简便的接口与回调函数来构建有限状态机,根据不同的返回参数在不同的状态间进行切换,也具备了同步或异步事件的处理。
Gen_fsm行为实践与分析的更多相关文章
- C++ Primer 学习笔记_46_STL实践与分析(20)--容器特有的算法
STL实践与分析 --容器特有的算法 与其它顺序容器所支持的操作相比,标准库为list容器定义了更精细的操作集合,使它不必仅仅依赖于泛型操作.当中非常大的一个原因就是list容器不是依照内存中的顺序进 ...
- C++ Primer 学习笔记_32_STL实践与分析(6) --再谈string类型(下)
STL实践与分析 --再谈string类型(下) 四.string类型的查找操作 string类型提供了6种查找函数,每种函数以不同形式的find命名.这些操作所有返回string::size_typ ...
- C++ Primer 学习笔记_44_STL实践与分析(18)--再谈迭代器【下】
STL实践与分析 --再谈迭代器[下] 三.反向迭代器[续:习题] //P355 习题11.19 int main() { vector<int> iVec; for (vector< ...
- C++ Primer 学习笔记_40_STL实践与分析(14)--概要、先来看看算法【上】
STL实践与分析 --概述.初窥算法[上] 标准库容器定义的操作很少.并没有给容器加入大量的功能函数.而是选择提供一组算法,这些算法大都不依赖特定的容器类型,是"泛型"的. ...
- C++ Primer 学习笔记_45_STL实践与分析(19)--建筑常规算法
STL实践与分析 --泛型算法的结构 引言: 正如全部的容器都建立在一致的设计模式上一样,算法也具有共同的设计基础. 算法最主要的性质是须要使用的迭代器种类.全部算法都指定了它的每一个迭代器形參可使用 ...
- C++ Primer 学习笔记_33_STL实践与分析(7) --容器适配器
STL实践与分析 --容器适配器 引: 除了顺序容器.标准库还提供了三种顺序容器适配器:queue,priority_queue和stack.适配器是标准库中的概念.包含容器适配器,迭代器适配器和函数 ...
- C++ Primer 学习笔记_35_STL实践与分析(9)--map种类(在)
STL实践与分析 --map类型(上) 引: map是键-值对的集合. map类型通常能够理解为关联数组:能够通过使用键作为下标来获取一个值,正如内置数组类型一样:而关联的本质在于元素的值与某个特定的 ...
- C++ Primer 学习笔记_41_STL实践与分析(15)--先来看看算法【下一个】
STL实践与分析 --初窥算法[下] 一.写容器元素的算法 一些算法写入元素值.在使用这些算法写元素时一定要当心.必须.写入输入序列的元素 写入到输入序列的算法本质上是安全的--仅仅会写入与指定输入范 ...
- C++ Primer 学习笔记_38_STL实践与分析(12)--集成的应用程序容器:文本查询程序
STL实践与分析 --容器的综合应用:文本查询程序 引言: 本章中最重点的实例.由于不须要用到multiset与multimap的内容.于是将这一小节提到了前面.通过这个实例程序,大师分析问题的智慧, ...
随机推荐
- Kinetic使用注意点--group
new Group(config) 参数: config:包含所有配置项的对象. { x: "横坐标", y: "纵坐标", width: "宽度&q ...
- 黑马程序员 SaveFileDialog的跨线程调用 (专题三)
<a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IO开发S</a> ...
- Java内存区域与内存溢出异常(二)
了解Java虚拟机的运行时数据区之后,大致知道了虚拟机内存的概况,内存中都放了些什么,接下来将了解内存中数据的其他细节,如何创建.如何布局.如何访问.这里虚拟机以HotSpot为例,内存区域以Java ...
- c# 赋值后最后一项数据部分丢失
赋值,赋值后 原因,在添加后立即调用clear()清除数据....
- IOS项目集成ShareSDK实现第三方登录、分享、关注等功能(备用)
(1)官方下载ShareSDK iOS 2.8.8,地址:http://sharesdk.cn/ (2)根据实际情况,引入相关的库,参考官方文档. (3)在项目的AppDelegate中一般情况下有三 ...
- 转载:传说中的T检验
第二周结束:传说中的T检验 小耿2014-01-21 10:58 本文和上一篇笔记一样:语言十分啰嗦.请大家忍耐…… 以前我不懂统计的时候(现在也不懂),只知道数据出来了要做三件事:1,检验一下数据是 ...
- Contest2037 - CSU Monthly 2013 Oct (Problem J: Scholarship)
http://acm.csu.edu.cn/OnlineJudge/problem.php?cid=2037&pid=9 [题解]: 这题卡了一下,卡在负数的情况,负数输出 0 这题主要找到一 ...
- tcpprep 对IPV6的支持
在采用tcpreplay对包实施回放前,需要对包执行预处理,tcpprep就是完成这个任务的.tcpprep要做的处理就是生成一个cache文件,根据tcpprep wiki的介绍http://tcp ...
- 如果Android和C#在一起?
先看两则新闻. 一则来自新浪科技: 谷歌上诉遭拒绝 需向甲骨文支付Java使用费 大意是说,针对谷歌Android操作系统侵犯甲骨文Java知识产权的指控,美国法院最近做出了有利于甲骨文的裁决 ...
- 4.0 spring-注册解析的Bean
1.0 registerBeanDefinition 对于配置文件,解析也解析完了,装饰也装饰完了,对于得到的BeanDefinition已经可以满足后续的使用了,唯一剩下的工作就是注册了, 也就是: ...