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

目 录CONTENT

文章目录
MC

NetWork

Dettan
2021-07-10 / 0 评论 / 0 点赞 / 185 阅读 / 1,325 字
温馨提示:
本文最后更新于 2022-07-23,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。
/ 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("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;
}
0

评论区