Java-неблокирующий клиент ввода-вывода получает данные с сервера - PullRequest
0 голосов
/ 01 ноября 2019

Я новичок в Java NIO и хочу создать программу, которая позволит пользователю вводить код продукта и его количество и отправлять на сервер. Затем сервер обработает цену товара и отправит цену клиенту. На стороне клиента будет отображаться цена товара

public class NIOProductServer {

    private Selector selector;

    private InetSocketAddress listenAddress;
    private final static int PORT = 9093;
    ArrayList<Product> products=new ArrayList<Product>();
    ArrayList<Integer> orderedItems=new ArrayList<Integer>();

    public static void main(String[] args) throws Exception {
        try {
            new NIOProductServer("localhost", 9093).startServer();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public NIOProductServer(String address, int port) throws IOException {
        listenAddress = new InetSocketAddress(address, PORT);

        // Initialize vairable and add to array list
        Product product1=new Product();
        Product product2=new Product();
        Product product3=new Product();

        product1.setName("Whopper");
        product1.setPrice(11.95);
        product1.setProductCode(101);

        product2.setName("Whopper with Cheese");
        product2.setPrice(14.15);
        product2.setProductCode(102);

        product3.setName("BK Double Mushroom Swiss");
        product3.setPrice(11.45);
        product3.setProductCode(103);

        products.add(product1);
        products.add(product2);
        products.add(product3);
    }

    /**
     * Start the server
     * 
     * @throws IOException
     */
    private void startServer() throws IOException {
        this.selector = Selector.open();
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);

        // bind server socket channel to port
        serverChannel.socket().bind(listenAddress);
        serverChannel.register(this.selector, SelectionKey.OP_ACCEPT);

        System.out.println("Server started on port >> " + PORT);

        while (true) {
            // wait for events
            int readyCount = selector.select();
            if (readyCount == 0) {
                continue;
            }

            // process selected keys...
            Set<SelectionKey> readyKeys = selector.selectedKeys();
            Iterator iterator = readyKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = (SelectionKey) iterator.next();

                // Remove key from set so we don't process it twice
                iterator.remove();

                if (!key.isValid()) {
                    continue;
                }

                if (key.isAcceptable()) { // Accept client connections
                    this.accept(key);
                } else if (key.isReadable()) { // Read from client
                    this.read(key);
                } else if (key.isWritable()) { // write data to client...
                    this.write(key);

                }
            }
        }
    }

    // accept client connection
    private void accept(SelectionKey key) throws IOException {
        ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
        SocketChannel channel = serverChannel.accept();
        channel.configureBlocking(false);
        Socket socket = channel.socket();
        SocketAddress remoteAddr = socket.getRemoteSocketAddress();
        System.out.println("Connected to: " + remoteAddr);

        /*
         * Register channel with selector for further IO (record it for read/write
         * operations, here we have used read operation)
         */
        channel.register(this.selector, SelectionKey.OP_READ);
    }

    // read from the socket channel
    private void read(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int numRead = -1;
        numRead = channel.read(buffer);

        if (numRead == -1) {
            Socket socket = channel.socket();
            SocketAddress remoteAddr = socket.getRemoteSocketAddress();
            System.out.println("Connection closed by client: " + remoteAddr);
            channel.close();
            key.cancel();
            return;
        }

        byte[] data = new byte[numRead];
        System.arraycopy(buffer.array(), 0, data, 0, numRead);
        String got=new String(data);
        System.out.println("Got: " + got);


        // Separate the string and find variable
        StringTokenizer tokenizer = new StringTokenizer(got, "\n");
        while (tokenizer.hasMoreTokens()) {
            String token = tokenizer.nextToken();
            StringTokenizer separator = new StringTokenizer(token, ":");
            String label = separator.nextToken();
            if (label.equalsIgnoreCase("Product Code")) {
                orderedItems.add(Integer.parseInt(separator.nextToken()));

            } else if (label.equalsIgnoreCase("Quantity")) {
                orderedItems.add(Integer.parseInt(separator.nextToken()));
            }

        }
        // Change the selector to write
        channel.register(this.selector, SelectionKey.OP_WRITE);

    }

    private void write(SelectionKey key) throws IOException {

        SocketChannel channel = (SocketChannel) key.channel();
        double subtotal=0;


        // This should print at client side


        System.out.println("Code\tName\t\t\tPrice\tQuantity\tSub Total");

        // loop to calculate product subtotal
        for(int i=0;i<orderedItems.size();i+=2) {
            for(Product p:products){
                if(p.getProductCode()==orderedItems.get(i)){
                    subtotal+=p.getPrice()*orderedItems.get(i+1);
                    System.out.print(p.getProductCode()+"\t"+p.getName()+"\t"+p.getPrice()+"\t\t"+orderedItems.get(i+1)+"\t\t");
                }
            }
        }
        System.out.println(subtotal+"\n");


        // remove unsed arraylist item 
        orderedItems.remove(1);
        orderedItems.remove(0);



        channel.register(this.selector, SelectionKey.OP_CONNECT);
    }
}

/ **************************************************************************** /

public class NIOProductClient {
public void startClient() throws IOException, InterruptedException {

    InetSocketAddress hostAddress = new InetSocketAddress("localhost", 9093);
    SocketChannel client = SocketChannel.open(hostAddress);

    System.out.println("Client... started");



    OrderedItem orderedItem1=new OrderedItem();

    // Get input from user and set into object
    Scanner scanner = new Scanner(System.in);
    System.out.println("\n\nEnter product code");
    orderedItem1.setProductCode(scanner.nextInt());
    System.out.println("Enter quantity");
    orderedItem1.setQuantity(scanner.nextInt());

    scanner.close();

    // Send messages to server
    String[] messages = new String[] { "Product Code:"+orderedItem1.getProductCode()+"\nQuantity:"+orderedItem1.getQuantity() };

    for (int i = 0; i < messages.length; i++) {
        ByteBuffer buffer = ByteBuffer.allocate(74);
        buffer.put(messages[i].getBytes());
        buffer.flip();
        client.write(buffer);
        System.out.println(messages[i]);
        buffer.clear();
        Thread.sleep(5000);
    }
    client.close();
}

public static void main(String[] args) {

    Runnable client = new Runnable() {
        @Override
        public void run() {
            try {
                new NIOProductClient().startClient();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    };

    new Thread(client, "client-A").start();
}

}

Все работает нормально, кроме функции записи на стороне сервера.

Клиент ожидал получить вывод, подобный этому

Код Имя Цена КоличествоИтого

103 BK Double Mushroom 11,45 2 22,9

...