Skip to content

Instantly share code, notes, and snippets.

@ksharpdabu
Created June 21, 2016 04:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ksharpdabu/6db4ac5435d97e23dede1ce1b542725e to your computer and use it in GitHub Desktop.
Save ksharpdabu/6db4ac5435d97e23dede1ce1b542725e to your computer and use it in GitHub Desktop.
java使用NIO实现EchoServer
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
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.util.Iterator;
import java.util.Set;
/**
* Created by AlexY on 2016/6/20.
* java使用NIO实现EchoServer
*/
public class MultiEchoServerNIO {
private static ServerSocketChannel serverSocketChannel;
private static final int PORT = 1234;
private static Selector selector;
/*
Above Selector used both for detecting new
connections (on the ServerSocketChannel) and for
detecting incoming data from existing connections
(on the SocketChannel).
*/
public static void main(String[] args) {
ServerSocket serverSocket;
System.out.println("Opening port…\n");
try {
serverSocketChannel = ServerSocketChannel.open();
System.out.println( serverSocketChannel.getClass().toString());
serverSocketChannel.configureBlocking(false);
serverSocket = serverSocketChannel.socket();
/*
ServerSocketChannel created before
ServerSocket largely in order to configure
latter as a non-blocking socket by calling
the configureBlocking method of the
ServerSocketChannel with argument of 'false'.
(ServerSocket will have a ServerSocketChannel
only if latter is created fi rst.)
*/
InetSocketAddress netAddress = new InetSocketAddress(PORT);
//Bind socket to port…
serverSocket.bind(netAddress);
//Create a new Selector object for detecting
//input from channels…
selector = Selector.open();
//Register ServerSocketChannel with Selector
//for receiving incoming connections…
serverSocketChannel.register(selector,
SelectionKey.OP_ACCEPT);
} catch (IOException ioEx) {
ioEx.printStackTrace();
System.exit(1);
}
processConnections();
}
private static void processConnections() {
do {
try {
//Get number of events (new connection(s)
//and/or data transmissions from existing
//connection(s))…
int numKeys = selector.select();
if (numKeys > 0) {
//Extract event(s) that have been
//triggered …
Set eventKeys =
selector.selectedKeys();
//Set up Iterator to cycle though set
//of events…
Iterator keyCycler = eventKeys.iterator();
while (keyCycler.hasNext()) {
SelectionKey key = (SelectionKey) keyCycler.next();
//Retrieve set of ready ops for
//this key (as a bit pattern)…
int keyOps = key.readyOps();
if (
(keyOps & SelectionKey.OP_ACCEPT)
== SelectionKey.OP_ACCEPT) {//New connection.
acceptConnection(key);
continue;
}
if (
(keyOps & SelectionKey.OP_READ)
== SelectionKey.OP_READ) {//Data from existing client.
acceptData(key);
}
}
}
} catch (IOException ioEx) {
ioEx.printStackTrace();
System.exit(1);
}
} while (true);
}
private static void acceptConnection(
SelectionKey key) throws IOException {//Accept incoming connection and add to list.
SocketChannel socketChannel;
Socket socket;
socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socket = socketChannel.socket();
System.out.println("Connection on "
+ socket + ".");
//Register SocketChannel for receiving data…
socketChannel.register(selector,
SelectionKey.OP_READ);
//Avoid re-processing this event as though it
//were a new one (next time through loop)…
selector.selectedKeys().remove(key);
}
private static void acceptData(SelectionKey key)
throws IOException {//Accept data from existing connection.
SocketChannel socketChannel;
Socket socket;
ByteBuffer buffer = ByteBuffer.allocate(2048);
//Above used for reading/writing data from/to
//SocketChannel.
socketChannel = (SocketChannel) key.channel();
buffer.clear();
int numBytes = socketChannel.read(buffer);
System.out.println(numBytes + " bytes read.");
socket = socketChannel.socket();
if (numBytes == -1)
//OP_READ event also triggered by closure of
//connection or error of some kind. In either
//case, numBytes = -1.
{
//Request that registration of this key's
//channel with its selector be cancelled…
key.cancel();
System.out.println("\nClosing socket "
+ socket + "…");
closeSocket(socket);
} else {
try {
/*
Reset buffer pointer to start of buffer,
prior to reading buffer's contents and
writing them to the SocketChannel…
重置buffer的指针指向buffer的开始,读取buffer中
内容,并写到SocketChannel
*/
buffer.flip();
while (buffer.remaining() > 0){
socketChannel.write(buffer);
}
} catch (IOException ioEx) {
System.out.println("\nClosing socket " + socket + "…");
closeSocket(socket);
}
}
//Remove this event, to avoid re-processing it
//as though it were a new one…
selector.selectedKeys().remove(key);
}
private static void closeSocket(Socket socket) {
try {
if (socket != null)
socket.close();
} catch (IOException ioEx) {
System.out.println(
"*** Unable to close socket! ***");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment