下面是一个通过 IPC 发送消息的完整方法。为了尽可能简单,publisher 和 subscriber 在同一线程上,但这在实际应用中并不合理。尽管如此,它还是非常有用的,因为它展示了一个最小 Aeron 应用程序的完整设置。代码可在
aeron-ipc
项目的 SimplestCase.java 文件中找到。作为示例的一部分,我们将构建以下4项:
- the Aeron API;
- the Media Driver;
- a Subscription;
- a Publication.
一、完整代码
public static void main(String[] args)
{
final String channel = "aeron:ipc";
final String message = "my message";
final IdleStrategy idle = new SleepingIdleStrategy();
final UnsafeBuffer unsafeBuffer = new UnsafeBuffer(ByteBuffer.allocate(256));
try (MediaDriver driver = MediaDriver.launch();
Aeron aeron = Aeron.connect();
Subscription sub = aeron.addSubscription(channel, 10);
Publication pub = aeron.addPublication(channel, 10))
{
while (!pub.isConnected())
{
idle.idle();
}
unsafeBuffer.putStringAscii(0, message);
System.out.println("sending:" + message);
while (pub.offer(unsafeBuffer) < 0)
{
idle.idle();
}
FragmentHandler handler = (buffer, offset, length, header) ->
System.out.println("received:" + buffer.getStringAscii(offset));
while (sub.poll(handler, 1) <= 0)
{
idle.idle();
}
}
}
执行结果
sending:my message
received:my message
二、剖析代码
构建基础支持对象定义
final String channel = "aeron:ipc";
final String message = "my message";
final IdleStrategy idle = new SleepingIdleStrategy();
final UnsafeBuffer unsafeBuffer = new UnsafeBuffer(ByteBuffer.allocate(256));
- 第 1 行指定 Aeron Publisher 和 Subscriber进行通信的channel,基于 Aeron URL 方式定义,本例中的channel为 IPC channel,另请参阅 Aeron Wiki on channel configuration 的内容。
- 第 2 行指定要通过publication发送的信息。
- 第 3 行指定了要使用的空闲策略,在本例中,空闲轮询时,
SleepingIdleStrategy
会将线程停等 1 us,默认值。- 第 4 行提供了一个堆外的不安全缓冲区,用于保存要发送的信息,为简单起见,分配了 256 字节,当然也可以减少。
构建 Aeron 对象
try (MediaDriver driver = MediaDriver.launch();
Aeron aeron = Aeron.connect();
Subscription sub = aeron.addSubscription(channel, 10);
Publication pub = aeron.addPublication(channel, 10))
接下来的四行代码将创建用于发送和接收数据的关键 Aeron 对象:
- 第 1 行创建Media Driver,Media Driver负责所有 IPC 和网络活动,稍后将详细讨论;
- 第 2 行创建 Aeron 对象。这是应用程序与 Aeron 交互的主要 API;
- 第 3 行创建Subscription,Subscription将被轮询以接收信息;
- 第 4 行创建用于发送消息的 Publication。
参考:Media Driver
发送消息
while (!pub.isConnected())
{
idle.idle();
}
unsafeBuffer.putStringAscii(0, message);
System.out.println("sending:" + message);
while (pub.offer(unsafeBuffer) < 0)
{
idle.idle();
}
这些代码负责发送消息;首先,应用程序等待
publication
连接完成;然后,将消息写入unsafeBuffer
,最后将buffer
提供给publication
,关键代码描述如下:
- 只有当
publication
连接后,第 1 行才返回 true。这是在一个 while 循环中进行轮询,每次轮询停等1us,直到连接成功;- 第 7 行向
publication
程序提供buffer,当返回的值小于零时,说明有什么东西阻止了publication
接受缓冲区,空闲策略再次进行轮询,直到它被接受为止。
接收消息
FragmentHandler handler = (buffer, offset, length, header) ->
System.out.println("received:" + buffer.getStringAscii(offset));
while (sub.poll(handler, 1) <= 0)
{
idle.idle();
}
代码的最后一部分负责接受来自
subscription
的消息。首先,由FragmentHandler
接收消息,然后对subscription
进行轮询,直到消息由 Aeron 接收。关键行如下:
- 第 1-2 行构建
FragmentHandler
,在本例中,我们知道这是一条简单的小消息,因此可以使用最基本的FragmentHandler
来接受消息,FragmentAssembler
应该用于重新组装较大的报文;- 第 4 行轮询
subscription
数据,与publication
一样,数值等于或小于零具有特定含义;然后,代码轮询subscription
,轮询空闲时间设置为1us。