FileDocCategorySizeDatePackage
TypeServer.javaAPI DocExample4875Sat Jul 31 20:37:30 BST 2004javathreads.examples.ch12.example3

TypeServer.java

package javathreads.examples.ch12.example3;

import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.net.*;
import java.util.*;
import javathreads.examples.ch12.*;

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();
    }
}