Java NIO-SocketChannel.write()在服务器上多次运行,但客户端只接收一次结果

Java NIO-SocketChannel.write()在服务器上多次运行,但客户端只接收一次结果,java,nio,nonblocking,socketchannel,Java,Nio,Nonblocking,Socketchannel,我正在做一个练习,需要使用Java非阻塞IO制作一个服务器-客户端聊天程序。目前,程序的工作方式很简单:当客户端向服务器发送消息时,服务器(已经跟踪所有客户端)将消息回显给所有客户端 这是我的部分服务器端代码: public static ByteBuffer str_to_bb(String msg) { try { return encoder.encode(CharBuffer.wrap(msg)); } catch(Exception e) {

我正在做一个练习,需要使用
Java非阻塞IO
制作一个服务器-客户端聊天程序。目前,程序的工作方式很简单:当客户端向服务器发送消息时,服务器(已经跟踪所有客户端)将消息回显给所有客户端

这是我的部分服务器端代码:

public static ByteBuffer str_to_bb(String msg) {
    try {
        return encoder.encode(CharBuffer.wrap(msg));
    } catch(Exception e) {
        e.printStackTrace();
    }
    return null;
}

private static void broadcastMessage(String nickname, String message) {
    System.out.println(">clientSocketChannels size " + clientSocketChannels.size());
    Iterator clientSocketChannelsIterator = clientSocketChannels.iterator();
    while (clientSocketChannelsIterator.hasNext()) {
        SocketChannel sc = (SocketChannel) clientSocketChannelsIterator.next();
        try {
            ByteBuffer bb = str_to_bb(message);
            System.out.println("bufferRemaining: " + bb.remaining()); // returns 2048
            int writeResult = sc.write(bb);
            System.out.println("writeResult: " + writeResult); // returns 2048
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
以下是我的客户端代码:

import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

/**
 * Created by ThaiSon on 7/6/2015.
 */
public class ChatRoomClientGUI {
    private JTextArea textAreaMessages;
    private JTextField textFieldMessage;
    private JButton buttonSendMsg;
    private JPanel jPanel1;
    private JLabel txtFieldInfo;

    private static InetAddress inetAddress;
    private static final int PORT = 1234;
    private static Socket socket = null;
    private static Scanner input = null;
    private static PrintWriter output = null;

    private static ChatRoomClientGUI singleton;

    public ChatRoomClientGUI() {
        singleton = this;
        buttonSendMsg.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                super.mouseClicked(e);
                if (e.getButton() == MouseEvent.BUTTON1) {
                    String message = textFieldMessage.getText();
                    output.println(message);
                    textFieldMessage.setText("");
                }
            }
        });
    }

    public static void main(String[] args) {
        JFrame promptFrame = new JFrame();
        Object nickname = JOptionPane.showInputDialog(promptFrame, "Enter your nickname:");
        promptFrame.dispose();

        JFrame frame = new JFrame("ChatRoomClientGUI");
        frame.setContentPane(new ChatRoomClientGUI().jPanel1);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);

        System.out.println("> Client with nickname " + nickname);

        try {
            inetAddress = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        accessServer(nickname.toString());
    }

    private static void accessServer(String nickname) {
        try {
            socket = new Socket(inetAddress, PORT);
            input = new Scanner(socket.getInputStream());
            output = new PrintWriter(socket.getOutputStream(), true);
            output.println(nickname); // Register nickname with the server

            //TODO update the txtFieldInfo content

            // Create a new thread to listen to InputStream event
            InputStreamEvent inputStreamEvent = new InputStreamEvent(socket);
            inputStreamEvent.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void handleInputStream(){
        String response = input.nextLine();
        System.out.println("TODO " + response);
        singleton.textAreaMessages.append(response + "\n");
    }

    static class InputStreamEvent extends Thread{
        Socket socket;
        public InputStreamEvent(Socket socket){
            this.socket = socket;
        }
        public void run(){
            try {
                InputStream inputStream = socket.getInputStream();
                byte[] buffer = new byte[2048];
                int read;
                while (true){
                    if(inputStream.available() > 0){
                        handleInputStream();
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
我现在面临的问题是,当我使用客户机(与旧的
多线程服务器
)向服务器发送消息时,客户机只返回它发送的第一条消息。来自服务器的所有后续响应都是空的(服务器确实会发回,但只发送一条空消息)

因此,我的调试尝试包括:

  • 检查来自客户端的消息是否已到达服务器。是的
  • 记录
    buffer.remaining()
    socketChannel.write(buffer)
    结果,如上所示,所有日志结果对我来说都是正常的
希望你们能帮我

  • 这:

    if(inputStream.available() > 0){
    
    摆脱这个测试。有了它,您的客户机正在抽CPU。如果没有它,它将按照上帝的意愿在
    readLine()
    中阻塞

  • 您确定您的服务器仍在发送线路吗?有线路终结者吗?否则,
    readLine()
    将永远阻止查找,直到流结束或出现异常为止


  • 我在这个链接上引用了EJP解释的代码

    它解决了我的问题。使用此代码

    设置此标志时我犯了错误
    key.interesttop(选择key.OP_READ);
    )
    而不是下面。 用这个
    socketChannel.register(this.selector、SelectionKey.OP|u WRITE、SelectionKey.OP|u READ);
    

    您确定在客户端上读取的内容正确吗?同一个客户端在旧的多线程服务器上运行良好,客户端可以准确显示服务器的第一个响应:/What is
    encoder
    clientSocketChannels
    encoder
    在这里:from
    public static Charset Charset=Charset.forName(“UTF-8”);公共静态CharsetEncoder=charset.newEncoder();公共静态CharsetDecoder=charset.newDecoder()
    (我从这个问题复制:)ClientSocketchannes是所有Socketchannes的ArrayList(每个SocketChannel都有一个连接到服务器的客户端),我相信这是因为扫描仪正在查找下一行,但您发送的消息末尾没有行分隔符。尝试在
    str\u to\u bb
    方法中执行
    CharBuffer.wrap(msg+“\r\n”)
    import java.nio.channels.SocketChannel;
    import java.nio.channels.Selector;
    import java.nio.ByteBuffer;
    import java.io.IOException;
    import java.util.Scanner;
    import java.nio.channels.SelectionKey;
    import java.net.InetSocketAddress;
    public class Client {
        public static void main(String args[]) {
            try {
                ByteBuffer buf = ByteBuffer.allocate(200);
                Scanner scanner = new Scanner(System.in);
                Selector selector = Selector.open();
                SocketChannel socketChannel = SocketChannel.open();
                socketChannel.configureBlocking(false);
                socketChannel.register(selector, SelectionKey.OP_CONNECT|SelectionKey.OP_READ|SelectionKey.OP_WRITE);
                boolean isConnected = socketChannel.connect(new InetSocketAddress("localhost", 5000));
                if(isConnected) {
                    System.out.println("Connected, de-registering OP_CONNECT");
                }
                new Thread(new Runnable(){
                    private SocketChannel socketChannel;
                    private Selector selector;
                    public Runnable init(SocketChannel socketChannel, Selector selector) {
                        this.socketChannel = socketChannel;
                        this.selector = selector;
                        return this;
                    }
                    public void run() {
                        try {
                            ByteBuffer buf = ByteBuffer.allocate(200);
                            while(!Thread.interrupted()) {
                                int keys = selector.select();
                                if(keys > 0) { 
                                    for(SelectionKey key : selector.selectedKeys()) {
                                        if(key.isConnectable()) {
                                            boolean finishConnectResult = socketChannel.finishConnect();
                                            socketChannel.register(this.selector, SelectionKey.OP_WRITE|SelectionKey.OP_READ);
                                            System.out.println("Finished Connect : " + finishConnectResult);
                                        }
                                        if(key.isReadable()) {
                                            int bytesRead = 0;
                                            while((bytesRead = socketChannel.read(buf)) > 0) {
                                                buf.flip();
                                                while(buf.hasRemaining()) {
                                                    System.out.print((char)buf.get());
                                                }
                                                buf.clear();
                                            }
                                            if(bytesRead == -1) {
                                                key.channel().close();
                                            }
                                        }
                                    }
                                }
                                Thread.sleep(10);
                            }
                        } catch(IOException e) {
                            e.printStackTrace();
                        } catch(InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }.init(socketChannel, selector)).start();
    
                while(true) {
                    while(scanner.hasNextLine()) {
                        buf.clear();
                        buf.put(scanner.nextLine().getBytes());
                        buf.flip();
                        socketChannel.write(buf);
                        buf.flip();
                    }
                }
            } catch(IOException e) {
                e.printStackTrace();
            }
        }
    }