Я новичок в StackOverflow lol, но на некоторое время я полагаюсь на этот сайт. У меня есть вопрос относительно созданного мной сервера сокетов Java. При подключении (клиент и сервер) мое приложение создает поток для этого клиента. Это игровой сервер MMORPG ... по крайней мере, пытаюсь быть. С одним игроком он не отстает от этого плохо. С двумя, однако, он начал показывать некоторые лаги ...Сервер Java Socket отстает от двух клиентов
Если бы я был спам слева-направо налево на одном из клиентов и мог нормально перемещаться с другим, другой мог бы чувствовать себя глючным. Я надеюсь получить помощника, так как я потратил более полутора недель, запутанных =) Пришло время попросить о помощи.
Код прост:
public static void main(String[] args) throws IOException{
serverRooms.put(roomNumber, new Room());
try {
System.out.println("Starting Server...");
serverSocket = new ServerSocket(9595, 20);
System.out.println("Server Started");
while(run){
Socket socket = serverSocket.accept(); // Check if we have a connection, otherwise wait
Player player = new Player(playerCount++, socket, roomNumber);
new Thread(player).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Вот как все это началось! На объекте игрока, он выглядит следующим образом:
public void run() {
while(playerIsConnected) {
try {
int msgid = input.readUnsignedByte();
messageHandler(this, msgid);
} catch (IOException e) {
System.err.println("Player have signed off");
playerIsConnected = false;
}
}
// If Player leaves, close socket, and end thread
try {
socket.close();
} catch (IOException e) {
System.out.println("We got an error while closing a socket on player " + pid + ".");
}
}
MessageHandler случается статический метод из конечного статического класса. Это глобальный метод, который может вызываться каждым потоком (Может ли это быть причиной отставания ??)
public final class MessageControl {
public static void messageHandler(Player player, int msgid) throws IOException{
DataInputStream input = player.getInputStream();
switch (msgid) {
case 10:
byte hspd = (byte) Math.signum(input.readByte());
byte vspd = (byte) Math.signum(input.readByte());
byte dir = input.readByte();
updatePlayerPosition(player);
byte spd = (byte) (hspd != 0 && vspd != 0 ? player.spd-1 : player.spd);
// Prepare packet and send to clients
ByteBuffer buffer = ByteBuffer.allocate(11);
buffer.put((byte) 10);
buffer.put(shortToByte_U16(player.pid));
buffer.put(shortToByte_U16(player.x));
buffer.put(shortToByte_U16(player.y));
buffer.put((byte)(hspd*spd));
buffer.put((byte)(vspd*spd));
buffer.put((byte)(dir));
sendPacketToAllClients(player, buffer, true);
// Update Player info
player.hspd = (byte) hspd;
player.vspd = (byte) vspd;
player.dir = dir;
player.lastUpdate = System.currentTimeMillis();
break;
}
private static void sendPacketToAllClients(Player player, ByteBuffer buffer, boolean includeMe){
for (Player otherPlayer : player.room.getPlayersInRoom()){
if (otherPlayer.pid != player.pid || includeMe){
sendPacketToClient(otherPlayer, buffer);
}
}
}
}
Что касается в shortToByte_U16(), я просто создал простой метод, который conerts шорты в байтах (отправка пакеты буферов через байты к клиенту). Пример, у меня есть около 5 из этих преобразований, которые будут включать в себя преобразование для неподписанных u16
public static byte[] shortToByte_16(int x){
short s = (short) x;
byte[] ret = new byte[2];
ret[0] = (byte)(s & 0xff);
ret[1] = (byte)((s >> 8) & 0xff);
return ret;
}
Глядя на следующую структуру, любые идеи, почему я быть отстаем?
EDIT: Я думаю, что я улучшил его, установив setTcpNoDelay в true. Кажется, что отставание остается, когда я спам слева и справа на моем конце ... другой игрок на моем экране кажется глючным.
Socket socket = serverSocket.accept(); // Check if we have a connection, otherwise wait
socket.setTcpNoDelay(true); // This helped a lot!!!
Player player = new Player(playerCount++, socket, roomNumber);
new Thread(player).start();
Из того, что я вижу ... мой «спамить влево/вправо» конец, кажется, отсутствует пакет, посланный сервером.
Я заметил, что messageHandler находится в цикле while. Как часто он вызывается, когда вы спам влево-вправо? Если ваш сервер получает тонну сообщений каждую секунду, которые он должен читать и обрабатывать, это может быть ресурсоемким. – faraza
Он называет один раз влево или вправо. «Int msgid = input.readUnsignedByte()» приостанавливает цикл while, поэтому я могу поместить инструкцию печати внутри, и она только печатает один раз перед остановкой. Когда пользователь нажимает LEFT или RIGHT, он снова печатает на каждую нажатую клавишу/полученное сообщение – AlbertGeno
Можете ли вы поместить println в sendPacketToAllClients, чтобы узнать, как часто это вызвано? – faraza