private void recv(SocketChannel sc, ClientInfo ci) throws IOException { ci.channel.read(ci.inBuf); ByteBuffer tmpBuf = ci.inBuf.duplicate(); tmpBuf.flip(); int bytesProcessed = 0; boolean doneLoop = false; while (!doneLoop) { byte b; try { b = tmpBuf.get(); } catch (BufferUnderflowException bue) { // Processed all data in buffer ci.inBuf.clear(); doneLoop = true; break; } switch (b) { case TypeServerConstants.WELCOME: bytesProcessed++; break; case TypeServerConstants.GET_STRING_REQUEST: bytesProcessed++; if (ci.outputPending) { // Client is backed up. We can't append to // the byte buffer because it's in the wrong // state. We could allocate another buffer // here and change our send method to know // about multiple buffers, but we'll just // assume that the client is dead break; } ci.outBuf.put(TypeServerConstants.GET_STRING_RESPONSE); ByteBuffer strBuf = encoder.encode(testString); ci.outBuf.putShort((short) strBuf.remaining()); ci.outBuf.put(strBuf); ci.outBuf.flip(); send(sc, ci); break; case TypeServerConstants.GET_STRING_RESPONSE: int startPos = tmpBuf.position(); try { int nBytes = tmpBuf.getInt(); byte[] buf = new byte[nBytes]; tmpBuf.get(buf); bytesProcessed += buf.length + 5; String s = new String(buf); // Send the string to the GUI break; } catch (BufferUnderflowException bue) { // Processed all available data ci.inBuf.position(ci.inBuf.position() + bytesProcessed); doneLoop = true; } break; } } }
// 感觉如果没有看过 NIO 的详细内容是不会懂这部分 public class TypeServer extends TCPNIOServer { static String testString = "Thisisateststring"; static class ClientInfo { ByteBuffer inBuf = ByteBuffer.allocateDirect(512); ByteBuffer outBuf = ByteBuffer.allocateDirect(512); boolean outputPending = false; SocketChannel channel; } Map allClients = new HashMap(); Charset encoder = Charset.forName("UTF-8"); protected void handleClient(SelectionKey key) throws IOException { SocketChannel sc = (SocketChannel) key.channel(); ClientInfo ci = (ClientInfo) allClients.get(sc); if (ci == null) throw new IllegalStateException("Unknown client"); if (key.isWritable()) send(sc, ci); if (key.isReadable()) // 从一个客户端读进所有的可用数据 recv(sc, ci); } private void recv(SocketChannel sc, ClientInfo ci) throws IOException { ci.channel.read(ci.inBuf); ByteBuffer tmpBuf = ci.inBuf.duplicate(); tmpBuf.flip(); int bytesProcessed = 0; boolean doneLoop = false; while (!doneLoop) { byte b; try { b = tmpBuf.get(); } catch (BufferUnderflowException bue) { // Processed all data in buffer ci.inBuf.clear(); doneLoop = true; break; } switch (b) { case TypeServerConstants.WELCOME: bytesProcessed++; break; case TypeServerConstants.GET_STRING_REQUEST: bytesProcessed++; if (ci.outputPending) { // Client is backed up. We can't append to // the byte buffer because it's in the wrong // state. We could allocate another buffer // here and change our send method to know // about multiple buffers, but we'll just // assume that the client is dead break; } ci.outBuf.put(TypeServerConstants.GET_STRING_RESPONSE); ByteBuffer strBuf = encoder.encode(testString); ci.outBuf.putShort((short) strBuf.remaining()); ci.outBuf.put(strBuf); ci.outBuf.flip(); send(sc, ci); break; case TypeServerConstants.GET_STRING_RESPONSE: int startPos = tmpBuf.position(); try { int nBytes = tmpBuf.getInt(); byte[] buf = new byte[nBytes]; tmpBuf.get(buf); bytesProcessed += buf.length + 5; String s = new String(buf); // Send the string to the GUI break; } catch (BufferUnderflowException bue) { // Processed all available data ci.inBuf.position(ci.inBuf.position() + bytesProcessed); doneLoop = true; } break; } } } private void send(SocketChannel sc, ClientInfo ci) throws IOException { int len = ci.outBuf.remaining(); int nBytes = sc.write(ci.outBuf); if (nBytes != len) { // Client not ready to receive data ci.outputPending = true; ci.channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); } else { ci.outBuf.clear(); if (ci.outputPending) { ci.outputPending = false; ci.channel.register(selector, SelectionKey.OP_READ); } } } protected void registeredClient(SocketChannel sc) throws IOException { ClientInfo ci = new ClientInfo(); ci.channel = sc; ci.outBuf.clear(); ci.outBuf.put(TypeServerConstants.WELCOME); ci.outBuf.flip(); allClients.put(sc, ci); send(sc, ci); } public static void main(String[] args) throws Exception { TypeServer ts = new TypeServer(); ts.port = Integer.parseInt(args[0]); Thread t = new Thread(ts); t.start(); System.out.println("Type server ready...Type CTRL-D to exit"); while (System.in.read() > 0) ; ts.stopServer(); t.join(); } }