Войти или зарегистрироваться

Помогите Асинхронная отправка пакетов

  • Автор темы Автор темы BeYkeR
  • Дата начала Дата начала

BeYkeR

Старожил
Девелопер
Пользователь
Баллы
173
После нескольких часов работы над минилизацией лагов для LightSource(при отправке пакета, сервер начинает сильно тормозить, или компьютер такой) у меня появилась одна мысль: Возможно ли отправить пакеты по асинхронному потоку ?
 
А что такое LightSource?
 
Вы занимались когда-нибудь клиент-серверным программированием?

Если нет, то вот вам ответ: весь ваш канал интернет-связи, однопоточен. Чем шире у вас канал, тем быстрее данные передаются. Но многопоточности тут и речи быть не может. Все данные выстраиваются в очередь и отправляются тоже по очереди.
 
Вы занимались когда-нибудь клиент-серверным программированием?

Если нет, то вот вам ответ: весь ваш канал интернет-связи, однопоточен. Чем шире у вас канал, тем быстрее данные передаются. Но многопоточности тут и речи быть не может. Все данные выстраиваются в очередь и отправляются тоже по очереди.

Можно ссылку на источник данной глупости? Здесь автор говорит про прикладной уровень, когда в любой другой программе можно из нескольких потоков отправлять различную информацию, а ты говоришь уже про уровень железа и про уровень операционной системы, когда идёт формирование пакетов на отправку.
 
@ptnk
Ну если по теме, Вы наверняка, в курсе. Сейчас насколько я понимаю, нет смысла озадачиваться отправкой пакетов в асинхронном потоке - это уже по идее выполняется самим сервером. По крайней мере, как-то Диннербон, что-то об этом говорил. Или нет? Я как-то так глубоко не копал.

@BeYkeR
Вообще, если говорить "на бытовом уровне", то как-то в моем плагине на ограничение террритории (аналог Borders, BorderGuard и т.п.) решил по границе нарисовать дымки. Т.е. каждые несколько секунд от сервера клиентам (всем игрокам) отправлялось несколько тысяч пакетов на отображение эффекта дыма.
Тормоза были. Но именно на уровне сети. Т.е. я банально перегрузил канал сервера, при этом TPS ни разу не упал.
 
Можно ссылку на источник данной глупости? Здесь автор говорит про прикладной уровень, когда в любой другой программе можно из нескольких потоков отправлять различную информацию, а ты говоришь уже про уровень железа и про уровень операционной системы, когда идёт формирование пакетов на отправку.

Через канал интернета всегда была отправка однопоточной. Все данные делятся на пакеты и отправляются. Если вы считаете что существует многопоточность, то это лишь иллюзия, пакеты могут добавляться асинхронно.
В любом случае, если уж говорить о майнкрафте, то клиент как принимал все в 1 потоке, так и будет принимать.
 
Через канал интернета всегда была отправка однопоточной. Все данные делятся на пакеты и отправляются. Если вы считаете что существует многопоточность, то это лишь иллюзия, пакеты могут добавляться асинхронно.

Если у меня есть канал 100МБит, значит считается, что я смогу отправить одновременно столько данных, если у клиенте есть столько - значит он столько сможет получить одновременно.

И мне, как java - программисту глубоко всё равно, как операционная система оперирует с каналом. У меня в секунду отправляется столько-то пакетов, за 1ms - столько-то данных, поэтому не нужно пудрить людям мозги с очередью и загружать их не нужной информации.
Любые данные одновременно отправленные из разных потоков придут к одному и тому же получателю с минимальной разницей.
 
Если у меня есть канал 100МБит, значит считается, что я смогу отправить одновременно столько данных, если у клиенте есть столько - значит он столько сможет получить одновременно.

И мне, как java - программисту глубоко всё равно, как операционная система оперирует с каналом. У меня в секунду отправляется столько-то пакетов, за 1ms - столько-то данных, поэтому не нужно пудрить людям мозги с очередью и загружать их не нужной информации.
Любые данные одновременно отправленные из разных потоков придут к одному и тому же получателю с минимальной разницей.

Хорошо, не буду пудрить никому мозг. Возможно, либо вы меня сначала не правильно поняли, либо я не очень понял автора.
 
Хорошо, не буду пудрить никому мозг. Возможно, либо вы меня сначала не правильно поняли, либо я не очень понял автора.
Задача: обмен данными в отдельных потоках с целью снижения нагрузки на основной поток.
 
Тормозить при отправке пакета? Нетворк итак в отдельных потоках выполняется.
Ваша проблема точно не в отправке пакета.
 
А что такое LightSource?
BukkitDev
@BeYkeR
Вообще, если говорить "на бытовом уровне", то как-то в моем плагине на ограничение террритории (аналог Borders, BorderGuard и т.п.) решил по границе нарисовать дымки. Т.е. каждые несколько секунд от сервера клиентам (всем игрокам) отправлялось несколько тысяч пакетов на отображение эффекта дыма.
Тормоза были. Но именно на уровне сети. Т.е. я банально перегрузил канал сервера, при этом TPS ни разу не упал.
Тормозить при отправке пакета? Нетворк итак в отдельных потоках выполняется.
Ваша проблема точно не в отправке пакета.
Написал -Lite версию плагина:
Код:
package ykt.BeYkeRYkt.LightSourceLite;

import java.util.ArrayList;
import java.util.List;

import net.minecraft.server.v1_7_R2.Chunk;
import net.minecraft.server.v1_7_R2.EnumSkyBlock;
import net.minecraft.server.v1_7_R2.PacketPlayOutMapChunk;
import net.minecraft.server.v1_7_R2.WorldServer;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.craftbukkit.v1_7_R2.CraftChunk;
import org.bukkit.craftbukkit.v1_7_R2.CraftServer;
import org.bukkit.craftbukkit.v1_7_R2.CraftWorld;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;

public class LSL extends JavaPlugin{

    public int task = 0;
    private static BlockFace[] SIDES = { BlockFace.UP, BlockFace.DOWN,
        BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST };

    private ArrayList<String> players = new ArrayList<String>();

    @Override
    public void onDisable() {
        getLogger().info("Disabled!");
        stopSyncTask();
    }

    @Override
    public void onEnable() {
        getLogger().info("Enabled!");
        startSyncTask();
    }

    public void stopSyncTask() {
        Bukkit.getScheduler().cancelTask(task);
    }


    public Block getAdjacentAirBlock(Block block) {
        for (BlockFace face : SIDES) {
            if (block.getY() == 0x0 && face == BlockFace.DOWN)
                continue;
            if (block.getY() == 0xFF && face == BlockFace.UP)
                continue;

            Block candidate = block.getRelative(face);

            if (candidate.getType().isTransparent()) {
                return candidate;
            }
        }
        return block;
    }

    public void startSyncTask(){
        task = Bukkit.getScheduler().runTaskTimer(this, new Runnable(){
            @Override
            public void run(){
                final List<String> playernames = new ArrayList<String>();
                for (int p = 0; p < Bukkit.getOnlinePlayers().length; p++) {
                    playernames.add(Bukkit.getOnlinePlayers()[p].getName());
                }
                Player player = null;
                for (final String playername : playernames) {
                    player = Bukkit.getPlayer(playername);
                    if (player != null) {
                        if (player.getInventory().getItemInHand().getType() == Material.TORCH) {
                        if(players.contains(player.getName())){
                          for(int x=-2; x <=2; x++){
                            for(int y=-2; y<=2; y++){
                              for(int z=-2; z<=2; z++){
                                Location loc = new Location(player.getWorld(), player.getLocation().getBlockX() + x, player.getLocation().getBlockY() + y, player.getLocation().getBlockZ() + z);
                               resetLight(loc);
                              }
                            }
                          }
                                lightUp(player.getLocation(), 14);
                                sendSyncPackets(player.getLocation());
                        }else{
                            players.add(player.getName());
                        }
                            }else{
                            if(players.contains(player.getName())){
                            for(int x=-2; x <=2; x++){
                             for(int y=-2; y<=2; y++){
                                for(int z=-2; z<=2; z++){
                                    Location loc = new Location(player.getWorld(), player.getLocation().getBlockX() + x, player.getLocation().getBlockY() + y, player.getLocation().getBlockZ() + z);
                                    resetLight(loc);
                                }
                             }
                            }
                               //resetLight(player.getLocation());
                                sendSyncPackets(player.getLocation());
                                players.remove(player.getName());
                            }
                            }
                   
                    }
                }
            }
        }, 0L, 7L).getTaskId();
    }


    public void lightUp(Location loc, int level) {
        WorldServer nmsWorld = ((CraftWorld) loc.getWorld()).getHandle();
   
        int x = loc.getBlockX();
        int y = loc.getBlockY();
        int z = loc.getBlockZ();
   
        nmsWorld.b(EnumSkyBlock.BLOCK, x, y, z, level);
    }

    public void resetLight(Location loc) {
        WorldServer nmsWorld = ((CraftWorld) loc.getWorld()).getHandle();
   
        int x = loc.getBlockX();
        int y = loc.getBlockY();
        int z = loc.getBlockZ();
   
        nmsWorld.c(EnumSkyBlock.BLOCK, x, y, z);   
    }

    public void sendSyncPackets(Location loc) {
        for(int x=-1; x<=1; x++) {
            for(int z=-1; z<=1; z++) {
                long startTime = System.currentTimeMillis();
                //Send       
                Chunk chunk = ((CraftChunk)loc.clone().add(16 * x, 0, 16 * z).getChunk()).getHandle();
                PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(chunk, false, '\uffff');
           
                Block adjacent = getAdjacentAirBlock(loc.getBlock());
                ((CraftWorld) loc.getWorld()).getHandle().t(adjacent.getX(), adjacent.getY(),adjacent.getZ());
                ((CraftServer) Bukkit.getServer()).getServer().getPlayerList().sendPacketNearby(loc.getX(), loc.getY(), loc.getZ(), 64, ((CraftWorld) loc.getWorld()).getHandle().dimension, packet);
                chunk.initLighting();
                long endTime = System.currentTimeMillis();
                getLogger().info("Sync: " + (endTime - startTime) + " ms!");
            }
        }
    }
}
Результат показывает ~10 - 20 миллисекунд. Со временем TPS падает до ~11 и держится там до тех пор, пока игрок не уберет факел. Во всех значениях period'a. Мне сейчас важно не вызывать частые лаги при использовании плагина.
 
Последнее редактирование:
Ваша проблема не в отправке пакета а в том что вы выполняете сложный расчётный таск каждый тик.
Вы видели сходный код метода World.c(EnumSkyBlock....)? Так вот он:
https://github.com/Bukkit/CraftBukk...in/java/net/minecraft/server/World.java#L2174
А ещё и chunk.initLightning().
https://github.com/Bukkit/CraftBukkit/blob/master/src/main/java/net/minecraft/server/Chunk.java#L174
Неудивительно что у вас тпс адово проседает.
 
Ваша проблема не в отправке пакета а в том что вы выполняете сложный расчётный таск каждый тик.
Вы видели сходный код метода World.c(EnumSkyBlock....)? Так вот он:
https://github.com/Bukkit/CraftBukk...in/java/net/minecraft/server/World.java#L2174
А ещё и chunk.initLightning().
https://github.com/Bukkit/CraftBukkit/blob/master/src/main/java/net/minecraft/server/Chunk.java#L174
Неудивительно что у вас тпс адово проседает.
Да уж, уже начинаю забывать смотреть на исходный код).
А что если я буду использовать старый метод вместо nmsWorld.c():
Код:
Location delete = new Location(loc.getWorld(), x, y, z);
Material blockMaterial = delete.getBlock().getType();
byte blockData = delete.getBlock().getData(); //Хотя зачем мне это ?
delete.getBlock().setType(blockMaterial);
delete.getBlock().setData(blockData);
и уберу chunk.initLightning() , TPS повысится ?
 
Назад
Верх