mercredi 1 février 2017

When to register OP_WRITE

I use NIO with reactor pattern to connect a server to a client. My codes are as follows: Server side codes, in the block of if(selectionKey.isWritable){} :

public void isWritable(SelectionKey selectionKey) throws Exception {

        SocketChannel socketChannel =
                (SocketChannel) selectionKey.channel();

        Integer myInteger = (Integer) selectionKey.attachment();

        if (myInteger == null){
            int myJob = jobFacade.isAnyJob(socketChannel, 100 /*deadline*/);
            if (myJob > 0){

                ByteBuffer inputBuffer = ByteBuffer.wrap("available\n".getBytes("UTF-8"));
                socketChannel.write(inputBuffer);
                myInteger = myJob;
                socketChannel.register(
                        selector, SelectionKey.OP_WRITE, myInteger);

            }else if (myJob == -1){

                ByteBuffer inputBuffer = ByteBuffer.wrap("unavailable\n".getBytes("UTF-8"));
                socketChannel.write(inputBuffer);
                socketChannel.close();

                UnsupportedOperationException un = new UnsupportedOperationException();
                throw un;

            }else if (myJob == -2){

                ByteBuffer inputBuffer = ByteBuffer.wrap("pending\n".getBytes("UTF-8"));
                inputBuffer.flip();
                socketChannel.write(inputBuffer);
                myInteger = null;
                socketChannel.register(
                        selector, SelectionKey.OP_WRITE, myInteger);

            }
//            is there any new job to do?
        }else{

            int myInt = myInteger.intValue();

            if ( myInt > 0 ){

                long startRange = jobFacade.findByID(myInt);
                sendTextFile(startRange, Integer.parseInt(properties.getProperty("workUnit")),
                             properties.getProperty("textPath"), socketChannel);
                myInteger = -3;
                socketChannel.register(
                        selector, SelectionKey.OP_WRITE, myInteger);

            }else if (myInt == -3){

                sendAlgorithmFile(socketChannel, properties.getProperty("algorithmPath"));
                myInteger = -4;
                socketChannel.register(
                        selector, SelectionKey.OP_WRITE, myInteger);
//                send algorithm file

            }else if (myInt == -4){
                int isOK = jobFacade.isAccepted(socketChannel.socket().getInetAddress().toString(),
                                                Long.parseLong(properties.getProperty("deadline")));
                if(isOK == -1){

                    ByteBuffer inputBuffer = ByteBuffer.wrap("notaccepted\n".getBytes("UTF-8"));
                    socketChannel.write(inputBuffer);
                    myInteger = null;
                    socketChannel.register(
                            selector, SelectionKey.OP_WRITE, myInteger);
                }else {

                    ByteBuffer inputBuffer = ByteBuffer.wrap("accepted\n".getBytes("UTF-8"));
                    socketChannel.write(inputBuffer);
                    myInteger = isOK;
                    socketChannel.register(
                            selector, SelectionKey.OP_READ, myInteger);
                }
//                send "accepted" or "not accepted"
            }
        }
    }

It is no need to know what my methods in each block do except that these methods generate a number with this order at first. 1)myInteger=null, 2) myInteger > 0, 3) myInteger = -3, 4) myInteger = -4 In this order, OP-WRITE will register consecutively for four times. And this part is so important. So lets see my Client side code and then I will tell you my problem:

BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            sentence = inFromServer.readLine();
            System.out.println("Response from Server : " + sentence);


            if (sentence.equals("available")){

                BufferedReader inFromServer1 = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                while ((sentence = inFromServer1.readLine()) != null) {
                     myJob = myJob + sentence ;
                }


inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                String acception = inFromServer.readLine();
                if (acception.equals("accepted")){

                    File file = new File("account.json");
                    byte[] bytes = new byte[2048];
                    InputStream inputStream = new FileInputStream(file);
                    OutputStream outputStream = clientSocket.getOutputStream();
                    int count;
                    try {
                        while ((count = inputStream.read(bytes)) > 0){
                            outputStream.write(bytes, 0, count);
                        }
                        outputStream.close();
                        inputStream.close();

                    }catch (IOException io){}

                    continue;

                }else if (acception.equals("notaccepted")){

                    continue;

                }

Now, my problem is that when I run my server and then my client, my server will run without waiting for my client to get input stream. First, the client get "available" but when the second getInputStream will be reached in client, the server paced all the phase of OP-WRITE registering and wait for client to get streams of data (As I defined in my code). Actually, my server do its job well. It will pass all the stages in required order. But the problem is that sending and receiving data is not synchronous. I do not know what my problem is. But I guess when I register OP-WRITE consecutively, it means that my server did not send all bytes of data, so just the first getInputStream will get the data. On the other hand, I need this order to run my program. So, Is there any Idea?

Aucun commentaire:

Enregistrer un commentaire