Jump to content
Sign in to follow this  
MURC

Error connect (GameServer)

Recommended Posts

Всем привет! Периодически, когда на 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
		}
	}
}

 

 

Дальше выбора сервера соответственно перестает пускать

Edited by MURC

Share this post


Link to post
Share on other sites

Пробовали сделать вот так

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...");
      }
    }

Но ошибка все равно появляется переодически, и дальше выбора сервера нельзя зайти.

Кто может дать совет, что делать

Share this post


Link to post
Share on other sites

Поменяй настройки  + если хочешь востановление соединение то надо дописывать реконект 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...