Selector.select()不会阻塞

时间:2014-04-05 19:10:51

标签: java selector

抱歉,在我发布此问题之前,我搜索了大约2天。有类似的问题,但没有一个帮助我。

我正在尝试创建一个简单的聊天应用程序,其中客户端使用(非NIO)Socket连接到侦听NIO ServerSocketChannel的服务器。服务器使用选择器。在第一个客户端连接之前,Selector.select()方法将被阻止,如预期的那样。但是在第一个客户端连接后,Selector.select()不会阻塞并立即返回。这导致我的while循环连续运行。

抱歉,我已粘贴整个代码,以便您可以复制粘贴并运行它。我刚刚开始使用Java,因此非常感谢任何帮助/指针。谢谢。

P.S。:现在,客户端通过套接字连接发送序列化对象(Message对象),Server读取它。由于连接是非阻塞的,因此序列化对象在发送到服务器之前预先固定了对象大小(以字节为单位)。这允许服务器读取下一个" x" bytes和un-serialize到Message对象。服务器代码正在进行中。

客户代码----------

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;

public class ChatClient {

    void go(){
        User u = new User();
        u.setName("UserA");
        try{
            u.setInet(InetAddress.getLocalHost());
        }catch (UnknownHostException ex){
            System.out.println(ex);
            return;
        }
        Message m = new Message();
        m.setType(3);
        m.setText("This is the 1st message.");
        m.setFromUser(u);
        try{
            Socket sock = new Socket (InetAddress.getLocalHost(), 5000);
            DataOutputStream dataOut = new DataOutputStream(sock.getOutputStream()); 
            ByteArrayOutputStream byteTemp = new ByteArrayOutputStream();
            ObjectOutputStream objOut = new ObjectOutputStream (byteTemp);
            objOut.writeObject(m);
            objOut.flush();
            objOut.close();

            byte[] byteMessage = byteTemp.toByteArray();
            ByteBuffer bb = ByteBuffer.allocate(4);
            bb.putInt(byteMessage.length);
            byte[] size = new byte[4];
            size = bb.array();
            System.out.println("Object size = "+byteMessage.length); //370

            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
            byteOut.write(size);
            byteOut.write(byteMessage);

            byte[] finalMessage = byteOut.toByteArray();
            dataOut.write(finalMessage,0,finalMessage.length);
            dataOut.flush();
            System.out.println("Flushed out");
        }catch (Exception ex){
            System.out.println(ex);
        }
    }

    public static void main (String args[]){
        new CopyOfChatClient().go();
    }
}

服务器代码---------------

    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    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.util.Iterator;
    import java.util.Set;
    import java.util.concurrent.locks.ReentrantLock;

    public class CopyOfChatServer {
        Object a, b;//Dummy objects for synchronization
        SocketChannel clientSock=null;
        Selector selector;
        SelectionKey key;

        void go(){
            try{
                a=new Object();//Dummy objects for synchronization
                b=new Object();//Dummy objects for synchronization
                ServerSocketChannel serverSock = ServerSocketChannel.open();
                serverSock.socket().bind(new InetSocketAddress(5000));
                //Note: ServerSocketChannel is blocking, but each new connection returned by accept() will be made non-blocking (see below)
                selector = Selector.open();
                new Thread(new SelectorThread()).start(); //Start the SelectorThread
                int i=0;
                while (true){               
                    clientSock = serverSock.accept();
                    if (clientSock!=null){                  
                        clientSock.configureBlocking(false); //The default client socket returned by accept() is blocking. Set it to non-blocking.                          
                        synchronized (b){
                            selector.wakeup();
                            synchronized (a){
                                key = clientSock.register(selector, SelectionKey.OP_READ);  //register new client Socket with selector  
                                key.attach(clientSock);
                            }//sync(a)
                        }//sync(b)              
                        i++;
                    }
                    System.out.println("Here");
                }//while(true)

            }catch (Exception ex){
                System.out.println(ex);
            }
        }

        class SelectorThread implements Runnable{
            Set <SelectionKey> selectedKeys;
            int readyChannels;
            public void run(){
                while (true){               
                        try {
                            synchronized(a){
                                System.out.println("1. Selector trying to select");
                                readyChannels = selector.select();//Note: select() is blocking ?? Does not block. Behaves like non-blocking
                                System.out.println("2. Selector has selected");
                            }//sync a

                            synchronized (b){
                                //just wait till registration is done in main thread
                            }

                            if (readyChannels == 0) continue; //Even if select() is blocking, this check is to handle suprious wake-ups
                            System.out.println("readyChannels>0");
                            selectedKeys = selector.selectedKeys();
                            Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
                            while (keyIterator.hasNext()){
                                SelectionKey key = keyIterator.next();
                    keyIterator.remove();//added after the first answer to my question
                                if (key.isReadable()){
                                    System.out.println("3. Got incoming data");
                                    SocketChannel tempSock = (SocketChannel)key.attachment();
                                    ByteBuffer bb=ByteBuffer.allocate(8000);
                                    int bytesRead=tempSock.read(bb);
                                    System.out.println("4. Bytes read = "+bytesRead);
                                    if (bytesRead>4){
                                        bb.flip();
                                        bb.rewind();

                                        int size = bb.getInt();
                                        System.out.println("5. Size of object = "+size);
                                        byte[] objIn = new byte[size];
                                        for (int i=0;i<size;i++){
                                            objIn[i]=bb.get();
                                        }
                                        bb.compact();

                                        ByteArrayInputStream bIn= new ByteArrayInputStream(objIn);
                                        ObjectInputStream objStream= new ObjectInputStream(bIn);
                                        Message temp1 = (Message) objStream.readObject();
                                        System.out.println("6. Read object back");
                                        System.out.println(temp1.getFromUser().getName());
                                    }
                                }
                            }
                            selectedKeys.clear();

                        } catch (IOException e) {
                            e.printStackTrace();
                        } catch (ClassNotFoundException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } 

                }
            }
        }

        public static void main (String args[]){
            new CopyOfChatServer().go();
        }
    }

MESSAGE Class ----

import java.io.Serializable;

public class Message implements Serializable{
    private int type; 
    private User fromUser;
    private User toUser;
    private String text;

    public int getType() {
        return type;
    }
    public void setType(int type) {
        this.type = type;
    }
    public User getFromUser() {
        return fromUser;
    }
    public void setFromUser(User fromUser) {
        this.fromUser = fromUser;
    }
    public User getToUser() {
        return toUser;
    }
    public void setToUser(User toUser) {
        this.toUser = toUser;
    }
    public String getText() {
        return text;
    }
    public void setText(String text) {
        this.text = text;
    }

}   

USER CLASS --------

import java.io.Serializable;
import java.net.InetAddress;

public class User implements Serializable{
    private String name;
    private InetAddress inet;


    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public InetAddress getInet() {
        return inet;
    }
    public void setInet(InetAddress inet) {
        this.inet = inet;
    }



}

1 个答案:

答案 0 :(得分:0)

你必须把

keyIterator.remove()

keyIterator.next()

选择器不会从selectedKeys()本身删除任何内容。

注意:您不需要将频道作为附件附加到密钥。你可以从key.channel()获得它。