NIO Java如何使同步客户端成为异步客户端?

时间:2013-12-17 07:26:46

标签: java asynchronous client nio

我有一个同步客户端,如何制作这个异步客户端?客户端连接正确,然后写入通道,然后等待(没有键准备好,因为没有任何东西可以从通道读取),现在我希望它再次开始写入通道,如何实现这一点?感谢

public class Client {
    static class SocketTest implements Runnable {


        private Selector selector;
        private int sessionID = 0;

        int port;
        String address;
        private List<Message> dummyTypeOneResults = new LinkedList<Message>();
        private List<Message> dummyTypeTwoResults = new LinkedList<Message>();

        public SocketTest(String address, int port){
            this.port = port;
            this.address = address;
        }

        @Override
        public void run() {
            SocketChannel channel;
            try {
                selector = Selector.open();
                channel = SocketChannel.open();
                channel.configureBlocking(false);

                channel.register(selector, SelectionKey.OP_CONNECT);
                channel.connect(new InetSocketAddress(this.address,this.port));

                while (!Thread.interrupted()){

                    selector.selectNow();

                    Iterator<SelectionKey> keys = selector.selectedKeys().iterator();


                    while (keys.hasNext()){
                        SelectionKey key = keys.next();
                        keys.remove();

                        if (!key.isValid()) continue;

                        if (key.isConnectable()){

                            connect(key);
                        }
                        if (key.isWritable()){

                            if(sessionID > 200000){
                                //force disconnect
                                System.out.println("sessionID reached limit forcing disconnet");
                                key.cancel();

                                //call calculate
                                calculate();
                                close();
                                return;

                                } else {
                                write(key);
                            }
                        }
                        if (key.isReadable()){
                            read(key);
                        }
                    }
                }
                } catch (IOException e1) {

                e1.printStackTrace();
                } finally {
                close();
            }
        }

        private void calculate() throws IOException{

            //open file


            File file = new File("results_nio.txt");

            // if file doesnt exists, then create it
            FileWriter fw = null;

            fw = new FileWriter(file.getAbsoluteFile());

            BufferedWriter bw = new BufferedWriter(fw);

            long totalDifferenceSum = 0;
            long messageCount = 0;
            for (Message message : dummyTypeOneResults) {
                long diff = message.getProcessed() - message.getDispatched();
                String out = "message with ID: "+message.getSessionID()+"  Trip time in seconds %f %n ";
                System.out.format(out,diff/1000000000.0);
                bw.write(String.format(out,diff/1000000000.0));
                totalDifferenceSum +=diff;
                messageCount++;
            }
            for (Message message : dummyTypeTwoResults) {
                long diff = message.getProcessed() - message.getDispatched();
                String out = "message with ID: "+message.getSessionID()+"  Trip time in seconds %f %n ";
                System.out.format(out,diff/1000000000.0);
                bw.write(String.format(out,diff/1000000000.0));
                totalDifferenceSum +=diff;
                messageCount++;
            }
            String totalString = "Total round trip time in seconds %f %n  ";
            System.out.format(totalString,totalDifferenceSum/1000000000.0);
            bw.write(String.format(totalString,totalDifferenceSum/1000000000.0));
            double average = messageCount > 0 ? (double)totalDifferenceSum/messageCount : 0;
            String averageString = "Average trip time in seconds %f %n  ";
            System.out.format(averageString,average/1000000000.0);
            bw.write(String.format(averageString,average/1000000000.0));
            bw.close();
        }

        private void close(){
            try {
                selector.close();
                } catch (IOException e) {
                System.err.println(e);
            }
        }

        private void read(SelectionKey key) throws IOException {
            SocketChannel channel = (SocketChannel) key.channel();
            ByteBuffer readBuffer = ByteBuffer.allocate(1024);

            int length;
            try {
                length = channel.read(readBuffer);
                System.out.println("Bytes read from server: "+length);
                if(length != -1){
                    byte[] bytes;
                    readBuffer.flip();
                    bytes = new byte[readBuffer.remaining()];
                    readBuffer.get(bytes, 0, bytes.length);

                    //create Message
                    ByteBuffer prepareBuffer = ByteBuffer.wrap(bytes);
                    int type = prepareBuffer.getInt();
                    int sessionID = prepareBuffer.getInt();
                    long dispatched = prepareBuffer.getLong();

                    Message message = new Message(sessionID, type, dispatched, bytes);
                    message.setProcessed(System.nanoTime());


                    if(type == Message.DUMMY_ONE){
                        dummyTypeOneResults.add(message);
                        } else if (type == Message.DUMMY_TWO) {
                        dummyTypeTwoResults.add(message);
                    }


                }

                } catch (IOException e) {
                System.out.println("Reading problem, closing connection");
                key.cancel();
                channel.close();
                return;
            }
            if (length == -1) {
                System.out.println("Nothing was read from server");
                //channel.close();
                key.cancel();
                System.out.println("Send againg new message ");
                key.interestOps(SelectionKey.OP_CONNECT);
                return;
            }
            readBuffer.flip();
            byte[] buff = new byte[1024];
            readBuffer.get(buff, 0, length);

            key.interestOps(SelectionKey.OP_WRITE);
            readBuffer.clear();

        }

        private void write(SelectionKey key) throws IOException {

            //Message format |typeID|sessionID|startTime

            SocketChannel channel = (SocketChannel) key.channel();
            ByteBuffer message = ByteBuffer.allocate(16);

            if(sessionID % 2 == 0){
                message.putInt(Message.DUMMY_ONE);
                } else {
                message.putInt(Message.DUMMY_TWO);
            }
            message.putInt(sessionID);
            message.putLong(System.nanoTime());
            sessionID++;

            message.flip();
            int bytesWritten = channel.write(message);
            System.out.println("client write(): bytesWritten :"+bytesWritten);


            // lets get ready to read.
            key.interestOps(SelectionKey.OP_READ);

        }

        private void connect(SelectionKey key) throws IOException {
            SocketChannel channel = (SocketChannel) key.channel();
            if (channel.isConnectionPending()){
                boolean finished = channel.finishConnect();
            if (!finished) {
                key.cancel();
            }
            }
            channel.configureBlocking(false);
            channel.register(selector,SelectionKey.OP_WRITE); // \p was
            //          channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
        }

    }

    public static void main(String[] args) {
        int DEFAULT_PORT = 9090;
        String IP = "127.0.0.1";

        if(args.length > 1){
            if(args[0]!=null){
                IP=args[0];
            }
            if(args[1]!=null){
                DEFAULT_PORT=Integer.valueOf(args[1]);
            }

        }

        new Thread(new SocketTest(IP,DEFAULT_PORT)).start();

    }

//和Message class

public class Message implements Serializable  {

    public static final int DUMMY_ONE = 1;
    public static final int DUMMY_TWO = 2;

    private static final long serialVersionUID = -555511105603152223L;

    // could be message header
    protected int sessionID;
    protected int type;
    protected long created = System.currentTimeMillis();
    protected long dispatched;
    protected long processed;
    protected Object payload;

    public Message(int sessionID, int type, long dispatched) {
    super();
    this.sessionID = sessionID;
    this.type = type;
    this.dispatched = dispatched;
    }

    public Message(int sessionID, int type, long dispatched, Object payload) {
    super();
    this.sessionID = sessionID;
    this.type = type;
    this.dispatched = dispatched;
        this.payload = payload;
    }

    public int getSessionID() {
    return sessionID;
    }

    public void setSessionID(int sessionID) {
     this.sessionID = sessionID;
    }

    public int getType() {
     return type;
    }

    public void setType(int type) {
     this.type = type;
    }

    public long getCreated() {
     return created;
    }

    public void setCreated(long created) {
     this.created = created;
    }

    public long getDispatched() {
     return dispatched;
    }

    public void setDispatched(long dispatched) {
     this.dispatched = dispatched;
    }

public long getProcessed() {
     return processed;
}

public void setProcessed(long processed) {
     this.processed = processed;
}

    public Object getPayload() {
    return payload;
    }

public void setPayload(Object payload) {
    this.payload = payload;
}

@Override
public String toString() {
    return "Message [sessionID=" + sessionID + ", type=" + type
            + ", created=" + created + ", dispatched=" + dispatched + "]";
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + (int) (created ^ (created >>> 32));
    result = prime * result + (int) (dispatched ^ (dispatched >>> 32));
    result = prime * result + ((payload == null) ? 0 : payload.hashCode());
    result = prime * result + (int) (processed ^ (processed >>> 32));
    result = prime * result + sessionID;
    result = prime * result + type;
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Message other = (Message) obj;
    if (created != other.created)
        return false;
    if (dispatched != other.dispatched)
        return false;
    if (payload == null) {
        if (other.payload != null)
            return false;
    } else if (!payload.equals(other.payload))
        return false;
    if (processed != other.processed)
        return false;
    if (sessionID != other.sessionID)
        return false;
    if (type != other.type)
        return false;
    return true;
}

}

1 个答案:

答案 0 :(得分:0)

你在'异步'和'非阻塞'之间感到困惑。

您正在非阻止模式下操作,但是您在select().阻止这是正常的。

如果您想要异步I / O,则需要使用AsynchronousSocketChannel。这是一个完全不同的编程范例。