我是JRakNet的创建者,这是一个网络库,它实现了Java的最新协议RakNet的基础知识。我创建了这个库,所以我可以为Minecraft制作一个多人游戏服务器:使用RakNet的Pocket Edition。
然而,我在服务器和客户端遇到的一个问题是处理程序的异常处理。无论何时发送无效数据包,都会错误地读取数据,并且会像正常情况一样抛出异常。但是,我需要找到一种方法来找出导致异常的外部地址。
通常,在使用ServerBootstrap的TCP服务器上,我能够对boss和worker组进行分组,因此当捕获到异常时,我知道它来自哪里,因为客户端拥有专用于它的自己的处理程序。但RakNet是UDP,这意味着它是无连接的,数据包可以来自任何地方,所以我只有一个处理程序。因此,每当抛出异常时,我都不知道是谁造成了它。我尝试过忽略异常列表,但我认为极效率低下。我已经尝试在代码中使用一个名为lastSender
的变量,因此无论何时抛出异常,它都会查找导致错误的原因。这是一个很好的方法来找出是谁造成了例外?或者是否有另一种更好的方法来确定谁在UDP Netty服务器上导致错误?
The RakNetClient class at the time of posting
The RakNetClientHandler classa at the time of posting
Here is the whole project code at the time of posting if needed
我需要找到一种好方法来确定哪个地址在原始Bootstrap Netty UDP服务器/客户端上导致异常。我曾尝试使用带有UDP的ServerBootstrap,但它似乎仍然只使用一个声明here
的频道答案 0 :(得分:1)
Netty有一个很好的线程模型since 4.0。
特别是
除非使用@Sharable注释ChannelHandler,否则Netty永远不会同时调用ChannelHandler的方法
有轻微change in 5.0但
从开发人员的角度来看,唯一改变的是,不再保证
ChannelHandler
将始终由同一个线程执行。但是,保证它永远不会被两个或多个线程同时执行。此外,Netty还将处理可能发生的任何内存可见性问题。因此,无需担心ChannelHandler
中的线程安全性和易失性变量。
你可以利用这个优势,只用
来解决问题static class UdpHandler extends SimpleChannelInboundHandler<DatagramPacket> {
private InetSocketAddress lastSender;
@Override
protected void messageReceived(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
lastSender = packet.sender();
throw new RuntimeException();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("Evil sender was: " + lastSender);
}
}
在exceptionCaught
之后直接调用messageReceived
方法
public static void invokeChannelReadNow(final ChannelHandlerContext ctx, final Object msg) {
try {
((AbstractChannelHandlerContext) ctx).invokedThisChannelRead = true;
ctx.handler().channelRead(ctx, msg); // -> calls messageReceived
} catch (Throwable t) {
notifyHandlerException(ctx, t); // -> calls exceptionCaught
}
}
本地变量的值仍将包含您在messageReceived
中设置的内容。