import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.*;
public class TcpServer {
private Selector m_selector;
private ServerSocketChannel m_channel;
private Map<SocketChannel, TcpServerConnection> m_channelMap;
private Thread m_thread;
private TcpServerListener m_listener;
private int m_port;
private boolean m_close;
public TcpServer(TcpServerListener listener, int port) {
m_port = port;
m_listener = listener;
m_close = false;
}
class SocketChannelComparator implements Comparator<SocketChannel> {
@Override
public int compare(SocketChannel o1, SocketChannel o2) {
return o1.hashCode() - o2.hashCode();
}
@Override
public boolean equals(Object obj) {
return (this == obj);
}
}
class TcpServerRunnable implements Runnable {
public void run() {
try {
m_selector = SelectorProvider.provider().openSelector();
m_channel = ServerSocketChannel.open();
InetSocketAddress addr = new InetSocketAddress(m_port);
m_channel.configureBlocking(false);
m_channel.socket().bind(addr);
System.out.println("Running...");
m_channel.register(m_selector, SelectionKey.OP_ACCEPT);
m_channelMap = new IdentityHashMap<SocketChannel, TcpServerConnection>();
} catch (IOException e) {
e.printStackTrace();
}
Iterator<SelectionKey> iterator;
try {
while (true) {
if (m_close)
return;
m_selector.select();
iterator = m_selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if (!key.isValid()) {
continue;
}
if (key.isConnectable()) {
SocketChannel m_socket = (SocketChannel) key.channel();
if (m_socket.isConnectionPending()) {
m_socket.finishConnect();
}
}
if (key.isAcceptable()) {
ServerSocketChannel socket = (ServerSocketChannel) key.channel();
SocketChannel client = socket.accept();
client.configureBlocking(false);
client.register(m_selector, SelectionKey.OP_READ);
m_channelMap.put(client, m_listener.onNewConnection(client));
}
if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
TcpServerConnection connection = m_channelMap.get(client);
try {
ByteBuffer data = ByteBuffer.allocate(client.socket().getReceiveBufferSize());
if (client.read(data) == -1) {
continue;
}
if (connection != null) {
data.flip();
connection.onDataReceived(data);
}
} catch (IOException e) {
if (connection != null) {
connection.onClosed();
m_channelMap.remove(client);
}
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public synchronized void runServer() {
m_thread = new Thread(new TcpServerRunnable());
m_thread.run();
}
public synchronized void closeServer() {
m_close = true;
try {
m_channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}