MURC 16 Опубликовано 30 июня, 2021 (изменено) Всем привет! Периодически, когда на 5-10 секунд пропадает сеть, gameserver выдает вот такую ошибку java.net.SocketException: Connection reset at java.base/sun.nio.ch.SocketChannelImpl.throwConnectionReset(SocketChannelImpl.java:345) at java.base/sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:376) at net.sf.l2j.commons.mmocore.SelectorThread.acceptConnection(SelectorThread.java:235) at net.sf.l2j.commons.mmocore.SelectorThread.run(SelectorThread.java:153) TRYING TO RECONNECT... Exception in thread "SelectorThread-93" java.lang.NullPointerException at net.sf.l2j.commons.mmocore.SelectorThread.readPacket(SelectorThread.java:261) at net.sf.l2j.commons.mmocore.SelectorThread.run(SelectorThread.java:157) Не могу понять, почему так происходит, кто может подсказать ? SelectorThread.java прикрепил и выложил под спойлер! Спасибо заранее Спойлер package net.sf.l2j.commons.mmocore; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; public final class SelectorThread<T extends MMOClient<?>> extends Thread { // default BYTE_ORDER private static final ByteOrder BYTE_ORDER = ByteOrder.LITTLE_ENDIAN; // default HEADER_SIZE private static final int HEADER_SIZE = 2; // Selector private final Selector _selector; // Implementations private final IPacketHandler<T> _packetHandler; private final IMMOExecutor<T> _executor; private final IClientFactory<T> _clientFactory; private final IAcceptFilter _acceptFilter; // Configurations private final int HELPER_BUFFER_SIZE; private final int HELPER_BUFFER_COUNT; private final int MAX_SEND_PER_PASS; private final int MAX_READ_PER_PASS; private final long SLEEP_TIME; public boolean TCP_NODELAY; // Main Buffers private final ByteBuffer DIRECT_WRITE_BUFFER; private final ByteBuffer WRITE_BUFFER; private final ByteBuffer READ_BUFFER; // String Buffer private final NioNetStringBuffer STRING_BUFFER; // ByteBuffers General Purpose Pool private final LinkedList<ByteBuffer> _bufferPool; // Pending Close private final NioNetStackList<MMOConnection<T>> _pendingClose; private boolean _shutdown; public SelectorThread(final SelectorConfig sc, final IMMOExecutor<T> executor, final IPacketHandler<T> packetHandler, final IClientFactory<T> clientFactory, final IAcceptFilter acceptFilter) throws IOException { super.setName("SelectorThread-" + super.getId()); HELPER_BUFFER_SIZE = sc.HELPER_BUFFER_SIZE; HELPER_BUFFER_COUNT = sc.HELPER_BUFFER_COUNT; MAX_SEND_PER_PASS = sc.MAX_SEND_PER_PASS; MAX_READ_PER_PASS = sc.MAX_READ_PER_PASS; SLEEP_TIME = sc.SLEEP_TIME; TCP_NODELAY = sc.TCP_NODELAY; DIRECT_WRITE_BUFFER = ByteBuffer.allocateDirect(sc.WRITE_BUFFER_SIZE).order(BYTE_ORDER); WRITE_BUFFER = ByteBuffer.wrap(new byte[sc.WRITE_BUFFER_SIZE]).order(BYTE_ORDER); READ_BUFFER = ByteBuffer.wrap(new byte[sc.READ_BUFFER_SIZE]).order(BYTE_ORDER); STRING_BUFFER = new NioNetStringBuffer(64 * 1024); _pendingClose = new NioNetStackList<>(); _bufferPool = new LinkedList<>(); for (int i = 0; i < HELPER_BUFFER_COUNT; i++) _bufferPool.addLast(ByteBuffer.wrap(new byte[HELPER_BUFFER_SIZE]).order(BYTE_ORDER)); _acceptFilter = acceptFilter; _packetHandler = packetHandler; _clientFactory = clientFactory; _executor = executor; _selector = Selector.open(); } public final void openServerSocket(InetAddress address, int tcpPort) throws IOException { final ServerSocketChannel selectable = ServerSocketChannel.open(); selectable.configureBlocking(false); selectable.socket().bind((address == null) ? new InetSocketAddress(tcpPort) : new InetSocketAddress(address, tcpPort)); selectable.register(_selector, SelectionKey.OP_ACCEPT); } final ByteBuffer getPooledBuffer() { if (_bufferPool.isEmpty()) return ByteBuffer.wrap(new byte[HELPER_BUFFER_SIZE]).order(BYTE_ORDER); return _bufferPool.removeFirst(); } final void recycleBuffer(final ByteBuffer buf) { if (_bufferPool.size() < HELPER_BUFFER_COUNT) { buf.clear(); _bufferPool.addLast(buf); } } @SuppressWarnings("unchecked") @Override public final void run() { int selectedKeysCount = 0; SelectionKey key; MMOConnection<T> con; Iterator<SelectionKey> selectedKeys; while (!_shutdown) { try { selectedKeysCount = _selector.selectNow(); } catch (IOException e) { e.printStackTrace(); } if (selectedKeysCount > 0) { selectedKeys = _selector.selectedKeys().iterator(); while (selectedKeys.hasNext()) { key = selectedKeys.next(); selectedKeys.remove(); con = (MMOConnection<T>) key.attachment(); switch (key.readyOps()) { case SelectionKey.OP_CONNECT: finishConnection(key, con); break; case SelectionKey.OP_ACCEPT: acceptConnection(key, con); break; case SelectionKey.OP_READ: readPacket(key, con); break; case SelectionKey.OP_WRITE: writePacket(key, con); break; case SelectionKey.OP_READ | SelectionKey.OP_WRITE: writePacket(key, con); if (key.isValid()) readPacket(key, con); break; } } } synchronized (_pendingClose) { while (!_pendingClose.isEmpty()) { try { con = _pendingClose.removeFirst(); writeClosePacket(con); closeConnectionImpl(con.getSelectionKey(), con); } catch (Exception e) { e.printStackTrace(); } } } try { Thread.sleep(SLEEP_TIME); } catch (InterruptedException e) { e.printStackTrace(); } } closeSelectorThread(); } private final void finishConnection(final SelectionKey key, final MMOConnection<T> con) { try { ((SocketChannel) key.channel()).finishConnect(); } catch (IOException e) { con.getClient().onForcedDisconnection(); closeConnectionImpl(key, con); } // key might have been invalidated on finishConnect() if (key.isValid()) { key.interestOps(key.interestOps() | SelectionKey.OP_READ); key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT); } } private final void acceptConnection(final SelectionKey key, MMOConnection<T> con) { ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); SocketChannel sc; for (int i = 0; i < 5; i++) { try { while ((sc = ssc.accept()) != null) { if (_acceptFilter == null || _acceptFilter.accept(sc)) { sc.configureBlocking(false); SelectionKey clientKey = sc.register(_selector, SelectionKey.OP_READ); ByteBuffer buffer = ByteBuffer.allocate(28); int n = sc.read(buffer); InetAddress address = sc.socket().getInetAddress(); if (n > 0) { address = InetAddress.getByAddress(Arrays.copyOfRange(buffer.array(), 16, 20)); } con = new MMOConnection<>(this, sc.socket(), clientKey, TCP_NODELAY, address); con.setClient(_clientFactory.create(con)); clientKey.attach(con); } else { if (sc != null && sc.socket() != null) { sc.socket().close(); } } } break; } catch (IOException e) { e.printStackTrace(); System.out.println("TRYING TO RECONNECT..."); } } } private final void readPacket(final SelectionKey key, final MMOConnection<T> con) { if (!con.isClosed()) { ByteBuffer buf; if ((buf = con.getReadBuffer()) == null) { buf = READ_BUFFER; } // if we try to to do a read with no space in the buffer it will read 0 bytes going into infinite loop if (buf.position() == buf.limit()) { closeConnectionImpl(key, con); return; } int result = -2; try { result = con.read(buf); } catch (IOException e) { // error handling goes bellow } if (result > 0) { buf.flip(); final T client = con.getClient(); for (int i = 0; i < MAX_READ_PER_PASS; i++) { if (!tryReadPacket(key, client, buf, con)) return; } // only reachable if MAX_READ_PER_PASS has been reached // check if there are some more bytes in buffer // and allocate/compact to prevent content lose. if (buf.remaining() > 0) { // did we use the READ_BUFFER ? if (buf == READ_BUFFER) // move the pending byte to the connections READ_BUFFER allocateReadBuffer(con); else // move the first byte to the beginning :) buf.compact(); } } else { switch (result) { case 0: case -1: closeConnectionImpl(key, con); break; case -2: con.getClient().onForcedDisconnection(); closeConnectionImpl(key, con); break; } } } } private final boolean tryReadPacket(final SelectionKey key, final T client, final ByteBuffer buf, final MMOConnection<T> con) { switch (buf.remaining()) { case 0: // buffer is full nothing to read return false; case 1: // we don`t have enough data for header so we need to read key.interestOps(key.interestOps() | SelectionKey.OP_READ); // did we use the READ_BUFFER ? if (buf == READ_BUFFER) // move the pending byte to the connections READ_BUFFER allocateReadBuffer(con); else // move the first byte to the beginning :) buf.compact(); return false; default: // data size excluding header size :> final int dataPending = (buf.getShort() & 0xFFFF) - HEADER_SIZE; // do we got enough bytes for the packet? if (dataPending <= buf.remaining()) { // avoid parsing dummy packets (packets without body) if (dataPending > 0) { final int pos = buf.position(); parseClientPacket(pos, buf, dataPending, client); buf.position(pos + dataPending); } // if we are done with this buffer if (!buf.hasRemaining()) { if (buf != READ_BUFFER) { con.setReadBuffer(null); recycleBuffer(buf); } else READ_BUFFER.clear(); return false; } return true; } // we don`t have enough bytes for the dataPacket so we need // to read key.interestOps(key.interestOps() | SelectionKey.OP_READ); // did we use the READ_BUFFER ? if (buf == READ_BUFFER) { // move it`s position buf.position(buf.position() - HEADER_SIZE); // move the pending byte to the connections READ_BUFFER allocateReadBuffer(con); } else { buf.position(buf.position() - HEADER_SIZE); buf.compact(); } return false; } } private final void allocateReadBuffer(final MMOConnection<T> con) { con.setReadBuffer(getPooledBuffer().put(READ_BUFFER)); READ_BUFFER.clear(); } private final void parseClientPacket(final int pos, final ByteBuffer buf, final int dataSize, final T client) { final boolean ret = client.decrypt(buf, dataSize); if (ret && buf.hasRemaining()) { // apply limit final int limit = buf.limit(); buf.limit(pos + dataSize); final ReceivablePacket<T> cp = _packetHandler.handlePacket(buf, client); if (cp != null) { cp._buf = buf; cp._sbuf = STRING_BUFFER; cp._client = client; if (cp.read()) _executor.execute(cp); cp._buf = null; cp._sbuf = null; } buf.limit(limit); } } private final void writeClosePacket(final MMOConnection<T> con) { SendablePacket<T> sp; synchronized (con.getSendQueue()) { if (con.getSendQueue().isEmpty()) return; while ((sp = con.getSendQueue().removeFirst()) != null) { WRITE_BUFFER.clear(); putPacketIntoWriteBuffer(con.getClient(), sp); WRITE_BUFFER.flip(); try { con.write(WRITE_BUFFER); } catch (IOException e) { // error handling goes on the if bellow } } } } protected final void writePacket(final SelectionKey key, final MMOConnection<T> con) { if (!prepareWriteBuffer(con)) { key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); return; } DIRECT_WRITE_BUFFER.flip(); final int size = DIRECT_WRITE_BUFFER.remaining(); int result = -1; try { result = con.write(DIRECT_WRITE_BUFFER); } catch (IOException e) { // error handling goes on the if bellow } // check if no error happened if (result >= 0) { // check if we written everything if (result == size) { // complete write synchronized (con.getSendQueue()) { if (con.getSendQueue().isEmpty() && !con.hasPendingWriteBuffer()) { key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); } } } else // incomplete write con.createWriteBuffer(DIRECT_WRITE_BUFFER); } else { con.getClient().onForcedDisconnection(); closeConnectionImpl(key, con); } } private final boolean prepareWriteBuffer(final MMOConnection<T> con) { boolean hasPending = false; DIRECT_WRITE_BUFFER.clear(); // if there is pending content add it if (con.hasPendingWriteBuffer()) { con.movePendingWriteBufferTo(DIRECT_WRITE_BUFFER); hasPending = true; } if (DIRECT_WRITE_BUFFER.remaining() > 1 && !con.hasPendingWriteBuffer()) { final NioNetStackList<SendablePacket<T>> sendQueue = con.getSendQueue(); final T client = con.getClient(); SendablePacket<T> sp; for (int i = 0; i < MAX_SEND_PER_PASS; i++) { synchronized (con.getSendQueue()) { if (sendQueue.isEmpty()) sp = null; else sp = sendQueue.removeFirst(); } if (sp == null) break; hasPending = true; // put into WriteBuffer putPacketIntoWriteBuffer(client, sp); WRITE_BUFFER.flip(); if (DIRECT_WRITE_BUFFER.remaining() >= WRITE_BUFFER.limit()) DIRECT_WRITE_BUFFER.put(WRITE_BUFFER); else { con.createWriteBuffer(WRITE_BUFFER); break; } } } return hasPending; } private final void putPacketIntoWriteBuffer(final T client, final SendablePacket<T> sp) { WRITE_BUFFER.clear(); // reserve space for the size final int headerPos = WRITE_BUFFER.position(); final int dataPos = headerPos + HEADER_SIZE; WRITE_BUFFER.position(dataPos); // set the write buffer sp._buf = WRITE_BUFFER; // set the client. sp._client = client; // write content to buffer sp.write(); // delete the write buffer sp._buf = null; // size (inclusive header) int dataSize = WRITE_BUFFER.position() - dataPos; WRITE_BUFFER.position(dataPos); client.encrypt(WRITE_BUFFER, dataSize); // recalculate size after encryption dataSize = WRITE_BUFFER.position() - dataPos; WRITE_BUFFER.position(headerPos); // write header WRITE_BUFFER.putShort((short) (dataSize + HEADER_SIZE)); WRITE_BUFFER.position(dataPos + dataSize); } final void closeConnection(final MMOConnection<T> con) { synchronized (_pendingClose) { _pendingClose.addLast(con); } } private final void closeConnectionImpl(final SelectionKey key, final MMOConnection<T> con) { try { // notify connection con.getClient().onDisconnection(); } finally { try { // close socket and the SocketChannel con.close(); } catch (IOException e) { // ignore, we are closing anyway } finally { con.releaseBuffers(); // clear attachment key.attach(null); // cancel key key.cancel(); } } } public final void shutdown() { _shutdown = true; } protected void closeSelectorThread() { for (final SelectionKey key : _selector.keys()) { try { key.channel().close(); } catch (IOException e) { // ignore } } try { _selector.close(); } catch (IOException e) { // Ignore } } } Дальше выбора сервера соответственно перестает пускать Изменено 30 июня, 2021 пользователем MURC Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
MURC 16 Опубликовано 3 июля, 2021 Пробовали сделать вот так private final void acceptConnection(final SelectionKey key, MMOConnection<T> con) { ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); SocketChannel sc; try { while ((sc = ssc.accept()) != null) { if (_acceptFilter == null || _acceptFilter.accept(sc)) { sc.configureBlocking(false); SelectionKey clientKey = sc.register(_selector, SelectionKey.OP_READ); ByteBuffer buffer = ByteBuffer.allocate(28); int n = sc.read(buffer); InetAddress address = sc.socket().getInetAddress(); if (n > 0) { address = InetAddress.getByAddress(Arrays.copyOfRange(buffer.array(), 16, 20)); } con = new MMOConnection<>(this, sc.socket(), clientKey, TCP_NODELAY, address); con.setClient(_clientFactory.create(con)); clientKey.attach(con); } else sc.socket().close(); } } catch (IOException e) { e.printStackTrace(); System.out.println("TRYING TO RECONNECT..."); } } Но ошибка все равно появляется переодически, и дальше выбора сервера нельзя зайти. Кто может дать совет, что делать Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты
terege 110 Опубликовано 4 июля, 2021 Поменяй настройки + если хочешь востановление соединение то надо дописывать реконект Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты