第三章 开发基于TCP的RPC服务
3.1 行为模式介绍
RPC表示远程过程调用(remote procedure call)。
行为模式是面向进程编程中各种常见模式的一种形式化表述。OTP行为模式将反复出现的模式分成两个部分:通用部分和具体应用相关的实现部分。
OTP中最常见最实用的行为模式就是gen_server通用服务器。
行为模式的组成部分:行为模式接口、行为模式实现、行为模式容器。
行为模式的接口是一组特定的函数和相关的调用规范。gen_server行为模式的接口包含六个函数:init/1、handle_call/3、handle_cast/2、handle_info/2、terminate/2和code_change/3。
实现,指的是由程序员提供的具体应用相关的代码。行为模式的实现是一个导出了接口所需的全部函数的回调模块。实现模块中还应包括一项属性-behaviour(...),用以说明该模块所实现的行为模式的名称,这样编译器可以协助检查模块是否完整地导出了接口所需的所有函数。
容器是一个进程,它执行的是某个库模块中的代码,并且会调用与行为模式实现相对应的回调模块来处理应用相关的逻辑。
3.2 行为模式实现
3.2.1 行为模式实现模块的典型布局
行为模式试下新模块的典型布局如下:

文件首部的文件级注释,每行注释以三个%开头,注释描述与的是关于整个文件的信息。注释中包括EDoc标注,EDoc可以直接通过源码标注生成文档。EDoc标签都以@开头,基本EDoc标签有:

%%%-------------------------------------------------------------------
%%% @doc
%%%
%%% @author
%%% @end
%%%------------------------------------------------------------------- 除去注释,文件的第一项是-module(...)属性,模块属性后面就是行为模式属性-behaviour(gen_server)。
接下来是导出声明,一个是自己实现的API,二是行为模式接口要求导出的函数。
行为模式的接口函数常被称作回调,因为容器启动时,行为模式实现模块的模块名会被传给新建的容器,容器随后又会通过接口函数反向调用实现模块。再之后是相关声明或预处理定义。
-module().
-behaviour(gen_server).
-export([
start_link/0
]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-include("common.hrl").
-include("notice.hrl").
-record(state, {}).
API段,模块的所有功能都是通过应用编程接口(API)提供给用户的。对于通用服务器而言,用户主要完成两件事:1.启动服务器进程 2.向进程发消息(并获取应答)。
屏蔽协议:
我们将进程能够接受的消息的集合称为该进程的协议。这些消息的细节是不能暴露给用户的,因此API的主要职责之一就是对外界屏蔽协议。
1.带外消息处理
采用call或cast以外的手段发送给gen_server进程的所有消息都由handle_info/2回调函数处理,这些消息被称为带外消息。当服务器需要与第三方模块通信,而第三方模块又以来与直接消息而非OTP库调用(比如套接字或端口驱动),就需要用到它。
主动套接字会以消息的形式将收到的所有数据都转发给建立套接字的进程,对于gen_server而言,这些数据都属于带外数据,所以由handle_info/2回调函数处理。
gen_server 超时事件
gen_server设置了超时之后,一旦超时触发,就会产生一条由原子timeout构成的带外消息,这条消息将由handle_info/2回调处理。该机制常用于处理服务器在超时时间内未收到任何请求的情况,此时可以用它来唤醒服务器并执行一些特定操作。
注:服务器不应该调用自身
通过RPC服务器,可以调用服务器任意模块中导出的任意函数,但是不能调用自己的API函数。假设在某个回调中向同一个服务器发起一个同步调用,服务器向自己发起gen_server:call(...)调用请求。而该请求只有在handle_info/2返回后才能得到处理,从而引发循环等待——服务器会陷入死锁。
3.4 浅谈测试
测试包括单元测试和集成测试。在Erlang/OTP标准发布镜像中包含两个测试框架:EUnit和Common Test。EUnit主要用于单元测试,Common Teset适合集成测试等大规模测试。