何时注册OP_WRITE

时间:2017-01-28 18:09:34

标签: java design-patterns nio nonblocking reactor

我使用带有reactor模式的NIO将服务器连接到客户端。我的代码如下: 服务器端代码,位于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"
            }
        }
    }

除了这些方法首先使用此顺序生成数字之外,无需知道每个块中的方法。 1)myInteger = null,2)myInteger> 0,3)myInteger = -3,4)myInteger = -4 按此顺序,OP-WRITE将连续注册四次。这一部分非常重要。所以让我们看看我的客户端代码然后我会告诉你我的问题:

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;

                }

现在,我的问题是当我运行我的服务器然后运行我的客户端时,我的服务器将在不等待我的客户端获取输入流的情况下运行。首先,客户获得"可用"但是当客户端到达第二个getInputStream时,服务器会调整OP-WRITE注册的所有阶段并等待客户端获取数据流(正如我在代码中定义的那样)。 实际上,我的服务器做得很好。它将按所需顺序通过所有阶段。但问题是发送和接收数据不是同步的。 我不知道我的问题是什么。但我想当我连续注册OP-WRITE时,这意味着我的服务器没有发送所有字节的数据,所以只有第一个getInputStream才能获得数据。 另一方面,我需要这个命令来运行我的程序。那么,有什么想法吗?

3 个答案:

答案 0 :(得分:0)

我发现了我的问题。我的代码没有问题。任何订单随时都可以注册OP_WRITE。最重要的是写入缓冲区并正确读取套接字。 实际上,当我第二次向我的客户发送东西时,我没有清除缓冲区。在这种情况下,我发现它,并纠正它。 但是当我向客户端发送一些字符然后想要发送文件时,因为在我的客户端,我有一个循环来获取所有字符,如果文件是通过相同的循环得到的内容。 这里的问题是我如何将它们分开?

答案 1 :(得分:-1)

在考虑模式之前,我会帮助您澄清问题:

您有一个线程/进程传递一条消息,要求另一个线程/进程对该消息进行操作。

接收方需要读取消息并可能启动它自己的一些子线程来执行该工作,因为它可以接收其他请求。

告诉发件人确认收到了请求会很高兴。

似乎有必要保护消息传递。因为如果您在阅读时遇到其他请求,您最终可能会处理垃圾。

您可以将nio配置为具有多个读取器和一个编写器,只需读取缓冲区的一部分等。检查how-tos,api docs。这是非常强大的

答案 2 :(得分:-1)

  

发送消息后

TCP中没有消息。它是一个字节流。发送方的两次写入很可能是通过接收方的一次读取来读取的。如果你想要消息,你必须自己实现它们,包括计数字,终结符,STX / ETX,XML等。