Java Akka连接中止

Java Akka连接中止,java,tcp,akka,Java,Tcp,Akka,我对Akka TCP IO有奇怪的行为,问题是连接重置,因为从处理程序或终止处理程序显式调用了TcpMessage.abort()。对等方未接收到Tcp.ConnectionClosed事件。例如: 处理程序onReceive @Override public void onReceive(Object msg) throws Exception { if (msg instanceof Tcp.ConnectionClosed) { log.info("Server C

我对Akka TCP IO有奇怪的行为,问题是连接重置,因为从处理程序或终止处理程序显式调用了
TcpMessage.abort()
。对等方未接收到
Tcp.ConnectionClosed
事件。例如:

处理程序onReceive

@Override
public void onReceive(Object msg) throws Exception {
    if (msg instanceof Tcp.ConnectionClosed) {
        log.info("Server ConnectionClosed: {}", msg);
        getContext().stop(getSelf());
    } else if (msg instanceof Tcp.Received){
        log.info("Aborting connection");
        getSender().tell(TcpMessage.abort(), getSelf());
    }
}
测试代码

new JavaTestKit(system) {{
     getSystem().actorOf(Props.create(Server.class, getRef()), "Server");
     Tcp.Bound bound = expectMsgClass(Tcp.Bound.class);

     ActorRef client = getSystem().actorOf(
     Props.create(Client.class, bound.localAddress(), getRef()), "Client");
     watch(client);
     expectMsgClass(Tcp.Connected.class);
     client.tell(new Message.Write(), getRef());

     expectTerminated(client);
}};
执行后记录

[INFO] [10/19/2013 22:13:22.730] [actorSystem-akka.actor.default-dispatcher-3] [akka://actorSystem/user/Client] Client Connected
[INFO] [10/19/2013 22:13:22.736] [actorSystem-akka.actor.default-dispatcher-3] [akka://actorSystem/user/Client] Sending Write to Handler
[INFO] [10/19/2013 22:13:22.767] [actorSystem-akka.actor.default-dispatcher-3] [akka://actorSystem/user/Server/$a] Aborting connection
[INFO] [10/19/2013 22:13:22.774] [actorSystem-akka.actor.default-dispatcher-3] [akka://actorSystem/user/Server/$a] Server ConnectionClosed: Aborted

java.lang.AssertionError: assertion failed: timeout (3 seconds) during expectMsg: Terminated Actor[akka://actorSystem/user/Client#423174850]
如果我在处理程序中将
TcpMessage.abort()
更改为
TcpMessage.close()

[INFO] [10/19/2013 22:17:06.243] [actorSystem-akka.actor.default-dispatcher-4] [akka://actorSystem/user/Client] Client Connected
[INFO] [10/19/2013 22:17:06.249] [actorSystem-akka.actor.default-dispatcher-4] [akka://actorSystem/user/Client] Sending Write to Handler
[INFO] [10/19/2013 22:17:06.278] [actorSystem-akka.actor.default-dispatcher-4] [akka://actorSystem/user/Server/$a] Aborting connection
[INFO] [10/19/2013 22:17:06.288] [actorSystem-akka.actor.default-dispatcher-6] [akka://actorSystem/user/Client] Client ConnectionClosed: PeerClosed
[INFO] [10/19/2013 22:17:06.288] [actorSystem-akka.actor.default-dispatcher-3] [akka://actorSystem/user/Server/$a] Server ConnectionClosed: Closed
服务器处理程序如何向远程客户端发出关闭错误连接的信号?如果我将中止从客户端发送到服务器,一切正常

编辑:

好的,找到问题的根源,只有在我尝试中止之前发送了Write命令时,中止命令才起作用。在客户端和服务器上。现在我需要弄清楚原因

EDIT2:

似乎中止消息被卡住了,若我创建了新的客户端,那个么到达第一个客户端的
ErrorClosed
,并向第二个客户端发送和预期相同的写入命令,执行客户端接收到的中止

new JavaTestKit(system) {{
    getSystem().actorOf(Props.create(Server.class, getRef()), "Server");
    Tcp.Bound bound = expectMsgClass(Tcp.Bound.class);

    ActorRef client = getSystem().actorOf(
            Props.create(Client.class, bound.localAddress(), getRef()), "Client");
    watch(client);
    expectMsgClass(Tcp.Connected.class);
    client.tell(new Message.Write(), getRef());
    expectNoMsg();

    ActorRef client2 = getSystem().actorOf(
           Props.create(Client.class, bound.localAddress(), getRef()), "Client2");
    watch(client2);
    expectMsgClass(Tcp.Connected.class);

    expectTerminated(client);

    client2.tell(new Message.Write(), getRef());

    expectTerminated(client2);
    expectNoMsg();
}};
和日志:

[INFO] [10/20/2013 00:48:05.923] [actorSystem-akka.actor.default-dispatcher-4] [akka://actorSystem/user/Client] Client Connected
[INFO] [10/20/2013 00:48:05.929] [actorSystem-akka.actor.default-dispatcher-4] [akka://actorSystem/user/Client] Sending Write to Handler
[INFO] [10/20/2013 00:48:05.959] [actorSystem-akka.actor.default-dispatcher-4] [akka://actorSystem/user/Server/$a] Aborting connection, connection actor: [Actor[akka://actorSystem/system/IO-TCP/selectors/$a/2#1767183113]]
[INFO] [10/20/2013 00:48:05.966] [actorSystem-akka.actor.default-dispatcher-6] [akka://actorSystem/user/Server/$a] Server ConnectionClosed: Aborted
[INFO] [10/20/2013 00:48:08.930] [actorSystem-akka.actor.default-dispatcher-6] [akka://actorSystem/user/Client2] Client Connected
[INFO] [10/20/2013 00:48:08.934] [actorSystem-akka.actor.default-dispatcher-3] [akka://actorSystem/user/Client] Client ConnectionClosed: ErrorClosed(An existing connection was forcibly closed by the remote host)
[INFO] [10/20/2013 00:48:08.936] [actorSystem-akka.actor.default-dispatcher-4] [akka://actorSystem/user/Client2] Sending Write to Handler
[INFO] [10/20/2013 00:48:08.937] [actorSystem-akka.actor.default-dispatcher-4] [akka://actorSystem/user/Server/$b] Aborting connection, connection actor: [Actor[akka://actorSystem/system/IO-TCP/selectors/$a/4#-598138943]]
[INFO] [10/20/2013 00:48:08.938] [actorSystem-akka.actor.default-dispatcher-4] [akka://actorSystem/user/Server/$b] Server ConnectionClosed: Aborted
[INFO] [10/20/2013 00:48:08.938] [actorSystem-akka.actor.default-dispatcher-7] [akka://actorSystem/user/Client2] Client ConnectionClosed: ErrorClosed(An existing connection was forcibly closed by the remote host)
EDIT3:


让它更清楚一点,问题是:我如何通知我的远程参与者处理程序哪个对等方崩溃了,以及
ErrorClosed
连接(它在远程端执行)。最后一条
ErrorClosed
消息总是被卡住,它没有消失,它只是位于选择器中的某个位置,只有在我执行另一个网络操作(将另一个参与者写入或连接到服务器)后才被推送到对等方。只有在中止前执行
Write
命令时,才会遇到此行为。这种行为与操作系统无关;我在Windows和Linux机器上进行了尝试,得到了相同的结果。

我并没有找到解决这个问题的可靠方法,但我做了一些事情来尽量减少总体影响

  • 不要显式使用RST(包括中止命令)。始终关闭与散热片的连接(关闭)。即使发生错误
  • 若参与者因错误而死亡,则信号连接关闭,这样连接可以正确关闭
  • 使用异步rep req数据传输机制传输大量数据(ZMQ)

  • 也可以实现heartbeat actor,但这似乎不是一个很好的主意,特别是Akka IO选择器自己在TCP套接字上运行heartbeat?

    我没有找到解决这个问题的可靠方法,但我做了一些事情来最小化总体影响

  • 不要显式使用RST(包括中止命令)。始终关闭与散热片的连接(关闭)。即使发生错误
  • 若参与者因错误而死亡,则信号连接关闭,这样连接可以正确关闭
  • 使用异步rep req数据传输机制传输大量数据(ZMQ)

  • 也可以实现heartbeat actor,但这似乎不是个好主意,特别是Akka IO选择器自己在TCP套接字上运行heartbeat?

    那么实际的问题是什么?问题是,如果我的远程actor崩溃,我如何向对等方发信号?在我发送了序列写入命令后,出现了一些错误。这是一个错误,问题是。抱歉耽搁了。那么实际的问题是什么呢?问题是,如果我的远程演员崩溃了,我如何向peer发出信号?在我发送了序列写入命令后,出现了一些错误。这是一个错误,问题是。抱歉耽搁了。