首页 > 代码库 > Akka学习笔记(2)-- Echo Server

Akka学习笔记(2)-- Echo Server

EchoServer

上篇文章里,我们用Akka写了一个简单的HelloWorld例子,对Akka(以及Actor模式)有了初步的认识。本文将用Akka写一个EchoServer,看看在Actor的世界里,如何使用TCP协议

Github项目

照例,EchoServer的代码被放在了Github上。EchoServer比HelloWorld稍微复杂一点,一共有三个类,如下图所示:

Main

这次先从主类入手:

main()方法的第一行创建了一个Actor系统,名字为mySystem。接下来的四行代码,请看下面的详细解释。

TCP Manager

Akka将整个TCP层抽象为一个Actor,这个Actor就是TCP Manager。在main()方法的第二行代码里,我们给Actor系统添加了一个TCP Manager,并和它的经纪人取得了联系:

ActorRef tcpManager = Tcp.get(mySystem).getManager();
现在我们的Actor系统看起来是这样:

Props

Props应该是Properties的缩写,它的作用是告诉Actor系统如何创建一个Actor。Props提供了四个工厂方法来创建Props实例,如下所示:

public static Props create(Class<?> type, Object[] os)
public static <T extends Actor> Props create(Class<T> type, Creator<T> crtr)
public static <T extends Actor> Props create(Creator<T> crtr)
public static Props create(Class<?> type, Seq<Object> seq)
main()方法的第三行使用了上面的第一个工厂方法,这个工厂方法有两个参数:一个Class,和一个数组(实际上是vararg)。第一个参数表示Actor的class,第二个参数是传递给Actor构造函数的参数。这样,Actor系统就知道如何根据Props创建(用反射调用构造函数)一个Actor实例。main()方法的第四行创建了一个Accepter,起名为accepter。Accepter需要用到tcpManager,这也是我们将tcpManager当做第二个参数传递给Props.create()方法的缘故。现在Actor系统变成了下面这样(我用虚线箭头来表示Actor之间的依赖关系):


main()方法的第五行给accepter发了一个消息:整数12345。告诉它绑定端口12345,开始监听TCP连接,准备echo服务。

Accepter

Accepter负责监听端口,然后把收到的tcp连接交给Handler去处理。Accepter稍微有点复杂,下面是全部代码:

构造函数是为了建立对tcpManager的依赖,下面详细介绍onReceive()方法:

  • 如果收到的消息是Integer类型(port),我们给tcpManager发送绑定消息,通知它绑定某个端口。
  • 如果tcpManager成功绑定端口,它会回应已绑定消息(Bound)。
  • 否则,回应绑定失败消息(CommandFailed),accepter通过调用getContext().stop()方法结束自己。
  • 成功绑定端口后,如果有连接到达,则会收到Connected消息。accepter通过调用getContext().actorOf()创建一个Handler,然后把它注册给tcpManager。之后tcpManager就会把与这个连接相关的消息发给handler,换句话说,这个连接被handler接管。

Actor之间的父子关系

在Actor系统内部,Actor们之间并不是只有简单的依赖(或引用)关系,而是可以形成父子关系:Actor可以创建子Actor,然后把子任务分配给它们去处理。一个Actor的Children是通过它的context来管理的,上面代码中,accepter通过getContext()来获得它自己的context,然后通过调用context的actorOf()方法创建子Actor。假设现在有两个客户端连接到了我们的echo服务器,那么整个Actor系统将是下面这样(Actor系统内的实线箭头表示父子关系):

Handler

最后一个类是Handler,它比较简单,代码如下所示:


Handler只处理两种消息:

  • Received消息告诉handler有消息到达,因为是echo服务器,所以并不关心到达的消息里面是什么内容。getSender()方法可以得到消息的发送者,也就是tcpManager。然后给tcpManager发一条Write消息,告诉它把数据原封不动的写回给客户端。
  • ConnectionClosed告诉handler连接已经断开,handler通过调用context的stop()方法结束自己短暂的生命。

测试EchoServer

启动EchoServer,然后可以通过telnet命令进行测试,这里就不详细说明了。

结论

要想用Akka写一个echo服务器,还是挺难的,需要了解Akka的很多方面。但是相对于Socket,或者NIO来说,Akka版的echo服务器显然更简单。


Akka学习笔记(2)-- Echo Server