NetworkSystem 这是总的网络类, 里面有一个初始化服务端监听本地端口的方法, 有客户端连接就新建个NetworkManager 并放到networkManagers里集中管理.
NetworkManager每一个channel一个,会设置到pipeline里,自动调用,但是包的处理逻辑不在这里. 这里就相当于把channel再封装了一下, 还有两个本地端连接服务器的方法. 有发送封包函数.
packet
Handler类里没有直接处理包,而是有一个packet父类,有许多各种类型的packet子类,每一种packet的处理方法都写在packet子类里. 所以Handler调用packet的处理方法来处理packet
启动Netty
netty客户端的启动类就在networkManager里,服务端的在NetworkSystem里.
分离式服务端使用的网络是 NetworkSystem .
EndPoint 存的是 ChannelFuture 类型的.
NetworkSystem类
.localAddress(address, port) 设置监听本地端口.
/**
* Adds a channel that listens on publicly accessible network ports
*/
public void addLanEndpoint(InetAddress address, int port) throws IOException
{
if (address instanceof java.net.Inet6Address) System.setProperty("java.net.preferIPv4Stack", "false");
synchronized (this.endpoints)
{
Class <? extends ServerSocketChannel > oclass;
LazyLoadBase <? extends EventLoopGroup > lazyloadbase;
if (Epoll.isAvailable() && this.mcServer.shouldUseNativeTransport())
{
oclass = EpollServerSocketChannel.class;
lazyloadbase = SERVER_EPOLL_EVENTLOOP;
LOGGER.info("Using epoll channel type");
}
else
{
oclass = NioServerSocketChannel.class;
lazyloadbase = SERVER_NIO_EVENTLOOP;
LOGGER.info("Using default channel type");
}
this.endpoints
.add(((ServerBootstrap)((ServerBootstrap)(new ServerBootstrap()).channel(oclass)).childHandler(new ChannelInitializer<Channel>()
{
protected void initChannel(Channel p_initChannel_1_) throws Exception
{
//每有一个连接就会新建一个channel
try
{
p_initChannel_1_.config().setOption(ChannelOption.TCP_NODELAY, Boolean.valueOf(true));
}
catch (ChannelException var3)
{
;
}
p_initChannel_1_.pipeline().addLast("timeout", new ReadTimeoutHandler(net.minecraftforge.fml.common.network.internal.FMLNetworkHandler.READ_TIMEOUT)).addLast("legacy_query", new LegacyPingHandler(NetworkSystem.this)).addLast("splitter", new NettyVarint21FrameDecoder()).addLast("decoder", new NettyPacketDecoder(EnumPacketDirection.SERVERBOUND)).addLast("prepender", new NettyVarint21FrameEncoder()).addLast("encoder", new NettyPacketEncoder(EnumPacketDirection.CLIENTBOUND));
NetworkManager networkmanager = new NetworkManager(EnumPacketDirection.SERVERBOUND);
NetworkSystem.this.networkManagers.add(networkmanager);
p_initChannel_1_.pipeline().addLast("packet_handler", networkmanager);
networkmanager.setNetHandler(new NetHandlerHandshakeTCP(NetworkSystem.this.mcServer, networkmanager));
}
}).group(lazyloadbase.getValue()).localAddress(address, port)).bind().syncUninterruptibly());
}
}
/**
* Sets the NetHandler for this NetworkManager, no checks are made if this handler is suitable for the particular
* connection state (protocol)
*/
public void setNetHandler(INetHandler handler)
{
Validate.notNull(handler, "packetListener");
LOGGER.debug("Set listener of {} to {}", this, handler);
this.packetListener = handler;
}
NetworkManager 接收到包后最后都会调用channelRead0, 这个方法里又会调用package里的处理包的方法,每一个包一个方法. 会把每个NetworkManager特定的Handler(packetListener)当做参数传入进去.
protected void channelRead0(ChannelHandlerContext p_channelRead0_1_, Packet<?> p_channelRead0_2_) throws Exception
{
if (this.channel.isOpen())
{
try
{
((Packet<INetHandler>)p_channelRead0_2_).processPacket(this.packetListener);
}
catch (ThreadQuickExitException var4)
{
;
}
}
}
Handler是指定的,
net.minecraft.network.handshake.client.C00Handshake.class
public void processPacket(INetHandlerHandshakeServer handler)
{
handler.processHandshake(this);
}
一环套一环.
net.minecraft.server.network.NetHandlerHandshakeTCP.class
/**
* There are two recognized intentions for initiating a handshake: logging in and acquiring server status. The
* NetworkManager's protocol will be reconfigured according to the specified intention, although a login-intention
* must pass a versioncheck or receive a disconnect otherwise
*/
public void processHandshake(C00Handshake packetIn)
{
if (!net.minecraftforge.fml.common.FMLCommonHandler.instance().handleServerHandshake(packetIn, this.networkManager)) return;
switch (packetIn.getRequestedState())
{
case LOGIN:
this.networkManager.setConnectionState(EnumConnectionState.LOGIN);
if (packetIn.getProtocolVersion() > 340)
{
ITextComponent itextcomponent = new TextComponentTranslation("multiplayer.disconnect.outdated_server", new Object[] {"1.12.2"});
this.networkManager.sendPacket(new SPacketDisconnect(itextcomponent));
this.networkManager.closeChannel(itextcomponent);
}
else if (packetIn.getProtocolVersion() < 340)
{
ITextComponent itextcomponent1 = new TextComponentTranslation("multiplayer.disconnect.outdated_client", new Object[] {"1.12.2"});
this.networkManager.sendPacket(new SPacketDisconnect(itextcomponent1));
this.networkManager.closeChannel(itextcomponent1);
}
else
{
this.networkManager.setNetHandler(new NetHandlerLoginServer(this.server, this.networkManager));
}
break;
case STATUS:
this.networkManager.setConnectionState(EnumConnectionState.STATUS);
this.networkManager.setNetHandler(new NetHandlerStatusServer(this.server, this.networkManager));
break;
default:
throw new UnsupportedOperationException("Invalid intention " + packetIn.getRequestedState());
}
}
channel
可以读写,还有一个eventLoop
处理包的方法
net.minecraft.network.NetworkSystem networkTick(){ networkmanager.processReceivedPackets(); } //这里是遍历所有networkManager来处理包
net.minecraft.network.NetworkManager processReceivedPackets 里调用 this.flushOutboundQueue(); 又调用 this.dispatchPacket(...)
net.minecraft.network.NetworkManager dispatchPacket
private void dispatchPacket(final Packet<?> inPacket, @Nullable final GenericFutureListener <? extends Future <? super Void >> [] futureListeners)
{
final EnumConnectionState enumconnectionstate = EnumConnectionState.getFromPacket(inPacket);
final EnumConnectionState enumconnectionstate1 = (EnumConnectionState)this.channel.attr(PROTOCOL_ATTRIBUTE_KEY).get();
if (enumconnectionstate1 != enumconnectionstate && !( inPacket instanceof net.minecraftforge.fml.common.network.internal.FMLProxyPacket))
{
LOGGER.debug("Disabled auto read");
this.channel.config().setAutoRead(false);
}
if (this.channel.eventLoop().inEventLoop())
{
if (enumconnectionstate != enumconnectionstate1 && !( inPacket instanceof net.minecraftforge.fml.common.network.internal.FMLProxyPacket))
{
this.setConnectionState(enumconnectionstate);
}
ChannelFuture channelfuture = this.channel.writeAndFlush(inPacket);
if (futureListeners != null)
{
channelfuture.addListeners(futureListeners);
}
channelfuture.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
}
else
{
this.channel.eventLoop().execute(new Runnable()
{
public void run()
{
if (enumconnectionstate != enumconnectionstate1 && !( inPacket instanceof net.minecraftforge.fml.common.network.internal.FMLProxyPacket))
{
NetworkManager.this.setConnectionState(enumconnectionstate);
}
ChannelFuture channelfuture1 = NetworkManager.this.channel.writeAndFlush(inPacket);
if (futureListeners != null)
{
channelfuture1.addListeners(futureListeners);
}
channelfuture1.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
}
});
}
}
内置服务器初始化 networkmanager
net.minecraft.client.Minecraft launchIntegratedServer()
this.displayGuiScreen(new GuiScreenWorking());
SocketAddress socketaddress = this.integratedServer.getNetworkSystem().addLocalEndpoint();
NetworkManager networkmanager = NetworkManager.provideLocalClient(socketaddress);
networkmanager.setNetHandler(new NetHandlerLoginClient(networkmanager, this, (GuiScreen)null));
networkmanager.sendPacket(new C00Handshake(socketaddress.toString(), 0, EnumConnectionState.LOGIN, true));
com.mojang.authlib.GameProfile gameProfile = this.getSession().getProfile();
if (!this.getSession().hasCachedProperties())
{
gameProfile = sessionService.fillProfileProperties(gameProfile, true); //Forge: Fill profile properties upon game load. Fixes MC-52974.
this.getSession().setProperties(gameProfile.getProperties());
}
networkmanager.sendPacket(new CPacketLoginStart(gameProfile));
this.myNetworkManager = networkmanager;
初始化
@SideOnly(Side.CLIENT)
public static NetworkManager provideLocalClient(SocketAddress address)
{
final NetworkManager networkmanager = new NetworkManager(EnumPacketDirection.CLIENTBOUND);
((Bootstrap)((Bootstrap)((Bootstrap)(new Bootstrap()).group(CLIENT_LOCAL_EVENTLOOP.getValue())).handler(new ChannelInitializer<Channel>()
{
protected void initChannel(Channel p_initChannel_1_) throws Exception
{
p_initChannel_1_.pipeline().addLast("packet_handler", networkmanager);
}
})).channel(LocalChannel.class)).connect(address).syncUninterruptibly();
return networkmanager;
}
初始化
/**
* Create a new NetworkManager from the server host and connect it to the server
*/
@SideOnly(Side.CLIENT)
public static NetworkManager createNetworkManagerAndConnect(InetAddress address, int serverPort, boolean useNativeTransport)
{
if (address instanceof java.net.Inet6Address) System.setProperty("java.net.preferIPv4Stack", "false");
final NetworkManager networkmanager = new NetworkManager(EnumPacketDirection.CLIENTBOUND);
Class <? extends SocketChannel > oclass;
LazyLoadBase <? extends EventLoopGroup > lazyloadbase;
if (Epoll.isAvailable() && useNativeTransport)
{
oclass = EpollSocketChannel.class;
lazyloadbase = CLIENT_EPOLL_EVENTLOOP;
}
else
{
oclass = NioSocketChannel.class;
lazyloadbase = CLIENT_NIO_EVENTLOOP;
}
((Bootstrap)((Bootstrap)((Bootstrap)(new Bootstrap()).group(lazyloadbase.getValue())).handler(new ChannelInitializer<Channel>()
{
protected void initChannel(Channel p_initChannel_1_) throws Exception
{
try
{
p_initChannel_1_.config().setOption(ChannelOption.TCP_NODELAY, Boolean.valueOf(true));
}
catch (ChannelException var3)
{
;
}
p_initChannel_1_.pipeline().addLast("timeout", new ReadTimeoutHandler(30)).addLast("splitter", new NettyVarint21FrameDecoder()).addLast("decoder", new NettyPacketDecoder(EnumPacketDirection.CLIENTBOUND)).addLast("prepender", new NettyVarint21FrameEncoder()).addLast("encoder", new NettyPacketEncoder(EnumPacketDirection.SERVERBOUND)).addLast("packet_handler", networkmanager);
}
})).channel(oclass)).connect(address, serverPort).syncUninterruptibly();
return networkmanager;
}
评论区