我对 Akka TCP IO 有奇怪的行为,问题是连接重置,由于TcpMessage.abort()
来自处理程序或Terminating
处理程序的显式调用。对等方未收到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
服务器处理程序如何向远程客户端发送错误关闭连接的信号?如果我将中止从客户端发送到服务器,一切正常。
编辑:
好的,找到问题的根源,仅当我在尝试中止之前发送写入命令时,中止命令才起作用。在客户端和服务器上。现在我需要弄清楚为什么。
编辑2:
似乎中止消息被卡住了,如果我创建新客户端然后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)
编辑3:
为了更清楚一点,问题是:我如何通知我的远程演员处理程序哪个对等方崩溃ErrorClosed
了以及连接(它在远程端进行)。最后ErrorClosed
一条消息总是被卡住,它并没有消失,它只是位于选择器中的某个位置,并且仅在我执行另一个网络操作(将另一个参与者写入或连接到服务器)后才推送到对等方。仅当我Write
在中止之前执行命令时才会遇到此行为。此行为与操作系统无关;我在 Windows 和 Linux 机器上试过,结果一样。