侧边栏壁纸
  • 累计撰写 781 篇文章
  • 累计创建 1 个标签
  • 累计收到 1 条评论
标签搜索
MC

NetWork

Dettan
2021-07-10 / 0 评论 / 0 点赞 / 108 阅读 / 10,011 字
温馨提示:
本文最后更新于 2022-04-30,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。
/ MC / NetWork
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(&quot;Using epoll channel type&quot;);
    }
    else
    {
        oclass = NioServerSocketChannel.class;
        lazyloadbase = SERVER_NIO_EVENTLOOP;
        LOGGER.info(&quot;Using default channel type&quot;);
    }

    this.endpoints
					.add(((ServerBootstrap)((ServerBootstrap)(new ServerBootstrap()).channel(oclass)).childHandler(new ChannelInitializer&lt;Channel&gt;()
    {
        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(&quot;timeout&quot;, new ReadTimeoutHandler(net.minecraftforge.fml.common.network.internal.FMLNetworkHandler.READ_TIMEOUT)).addLast(&quot;legacy_query&quot;, new LegacyPingHandler(NetworkSystem.this)).addLast(&quot;splitter&quot;, new NettyVarint21FrameDecoder()).addLast(&quot;decoder&quot;, new NettyPacketDecoder(EnumPacketDirection.SERVERBOUND)).addLast(&quot;prepender&quot;, new NettyVarint21FrameEncoder()).addLast(&quot;encoder&quot;, new NettyPacketEncoder(EnumPacketDirection.CLIENTBOUND));
            NetworkManager networkmanager = new NetworkManager(EnumPacketDirection.SERVERBOUND);
            NetworkSystem.this.networkManagers.add(networkmanager);
            p_initChannel_1_.pipeline().addLast(&quot;packet_handler&quot;, 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;
}
            <div style="color: inherit; fill: inherit;">
                <div style="display: flex;">
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() &gt; 340)
        {
            ITextComponent itextcomponent = new TextComponentTranslation(&quot;multiplayer.disconnect.outdated_server&quot;, new Object[] {&quot;1.12.2&quot;});
            this.networkManager.sendPacket(new SPacketDisconnect(itextcomponent));
            this.networkManager.closeChannel(itextcomponent);
        }
        else if (packetIn.getProtocolVersion() &lt; 340)
        {
            ITextComponent itextcomponent1 = new TextComponentTranslation(&quot;multiplayer.disconnect.outdated_client&quot;, new Object[] {&quot;1.12.2&quot;});
            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(&quot;Invalid intention &quot; + 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(&quot;Disabled auto read&quot;);
    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&lt;Channel&gt;()
{
    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(&quot;timeout&quot;, new ReadTimeoutHandler(30)).addLast(&quot;splitter&quot;, new NettyVarint21FrameDecoder()).addLast(&quot;decoder&quot;, new NettyPacketDecoder(EnumPacketDirection.CLIENTBOUND)).addLast(&quot;prepender&quot;, new NettyVarint21FrameEncoder()).addLast(&quot;encoder&quot;, new NettyPacketEncoder(EnumPacketDirection.SERVERBOUND)).addLast(&quot;packet_handler&quot;, networkmanager);
    }
})).channel(oclass)).connect(address, serverPort).syncUninterruptibly();
return networkmanager;

}

0

评论区