Сокет Java - PullRequest
       10

Сокет Java

0 голосов
/ 23 марта 2012

Я новичок в Java и пытаюсь написать простой клиентский сервер с TCP-сокетом, но у меня возникли проблемы после нескольких дней борьбы с ним, я не смог решить эту проблему.

Я получил значение NULL с помощью BufferReader.Readline ();

МОЙ код сервера:

Запустить код сервера

public class StartServer {
    ServerSocket server;
    public StartServer(){
        try {
            server = new ServerSocket(4444);
        } catch (Exception e) {
            System.out.println("server can't listen to this port");
        }
         System.out.println("Listening for clients on 4444..."); 
        int id =0;
        while(true)
        {
            try {
                Socket client = server.accept();
                ServerThread svThread = new ServerThread(client, id++);
                svThread.start();
            } catch (Exception e) {
                System.out.println("Error.......");
            }
        }
    }

    public static void main(String[] args) {
        new StartServer();
    }

}

Тема сервера:

public class ServerThread extends Thread{
    Socket client;
    int clientID = 0;
    boolean threadRun = true;
    BufferedReader inputFromClient = null;
    PrintWriter outputFromServer = null;

    public ServerThread(Socket socket, int cID) {
        client = socket;
        clientID = cID;
    }


    public void run() {
        try {
            inputFromClient = new BufferedReader(new InputStreamReader(client.getInputStream()));
            outputFromServer  = new PrintWriter(new OutputStreamWriter(client.getOutputStream()));
            System.out.println("ClientID: " + clientID);

            while(threadRun){
                String textFromClient = inputFromClient.readLine();
                System.out.println("Client ID: " + clientID + " Client says: " + textFromClient);

                if(textFromClient.equals("Quit")){
                    threadRun = false;
                    System.out.println("Stop client Thread from: " + clientID);
                }else{
                    outputFromServer.print(textFromClient);
                    outputFromServer.flush();
                }
            }
        } catch (IOException ex) {
            Logger.getLogger(ServerThread.class.getName()).log(Level.SEVERE, null, ex);
        }finally{
            try {
                inputFromClient.close();
                outputFromServer.close();
                client.close();
                System.out.println("Server Stopped...");
            } catch (Exception e) {
            }
        }
    }




}

Мой клиент, я использую JFrame, вызываю Panel и использую текстовое поле и jbutton для отправки сообщения на сервер

Но когда я отправляю одно сообщение, сервер может получить это сообщение и распечатать его в командной строке, но он продолжает пытаться получить сообщение от клиента (потому что оно находится внутри цикла while), но он получает ноль, я понятия не имею, в этой ситуации

мой код клиента:

Код JFrame:

public class NewJFrame extends javax.swing.JFrame {

    /**
     * Creates new form NewJFrame
     */

    Panel1 p ;
    public NewJFrame() {
        initComponents();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jDesktopPane1 = new javax.swing.JDesktopPane();
        jPanel1 = new javax.swing.JPanel();
        jButton1 = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jButton1.setText("jButton1");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
                .addContainerGap(196, Short.MAX_VALUE)
                .addComponent(jButton1)
                .addGap(91, 91, 91))
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGap(83, 83, 83)
                .addComponent(jButton1)
                .addContainerGap(134, Short.MAX_VALUE))
        );

        jPanel1.setBounds(0, 0, 360, 240);
        jDesktopPane1.add(jPanel1, javax.swing.JLayeredPane.DEFAULT_LAYER);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(jDesktopPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 365, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(0, 35, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(jDesktopPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 265, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(0, 35, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>                        

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        // TODO add your handling code here:
        p   = new Panel1();
        jDesktopPane1.removeAll();
        jDesktopPane1.repaint();
        jDesktopPane1.revalidate();
         p.setBounds(0, 0, 840, 558);
        p.setSize(840,558);
        jDesktopPane1.add(p);
        p.show();

    }                                        

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /*
         * Set the Nimbus look and feel
         */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /*
         * If Nimbus (introduced in Java SE 6) is not available, stay with the
         * default look and feel. For details see
         * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /*
         * Create and display the form
         */
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new NewJFrame().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify                     
    private javax.swing.JButton jButton1;
    private javax.swing.JDesktopPane jDesktopPane1;
    private javax.swing.JPanel jPanel1;
    // End of variables declaration                   
}

Код моей панели:

public class Panel1 extends javax.swing.JPanel {
 Socket s;
 PrintWriter outPut = null;
    /**
     * Creates new form Panel1
     */
    public Panel1() {
        initComponents();
        ConnectServer();
       //sendToServer();
       // receiveFromServer();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */

    public void ConnectServer(){
        try {
             s = new Socket("localhost", 4444);
             System.out.println("Connect to server");
             outPut = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
           //  PrintWriter outPut = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
            //outPut.println("Test cai coi.....");
            //outPut.flush();
        } catch (UnknownHostException ex) {
            Logger.getLogger(Panel1.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Panel1.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void receiveFromServer(){
        try {
            BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream()));
            System.out.println(input.readLine());
        } catch (IOException ex) {
            Logger.getLogger(Panel1.class.getName()).log(Level.SEVERE, null, ex);
        }

    }


    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jTextField1 = new javax.swing.JTextField();
        jButton1 = new javax.swing.JButton();

        jButton1.setText("jButton1");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(26, 26, 26)
                .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 138, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jButton1)
                .addContainerGap(157, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(34, 34, 34)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jButton1))
                .addContainerGap(243, Short.MAX_VALUE))
        );
    }// </editor-fold>                        

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
       //PrintWriter outPut = null;
        PrintWriter outToServer = null;
         BufferedReader input = null;
        try {
            // TODO add your handling code here:
            outToServer  = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));

            String txtFromClient = jTextField1.getText();
           // String clientText = input.readLine();
            System.out.println(txtFromClient);
            outToServer.println(txtFromClient);
            outToServer.flush();

            //





            //outPut.flush();
             //System.out.println(input.readLine());
        } catch (Exception ex) {
            Logger.getLogger(Panel1.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            //outPut.close();
             outToServer.close();
        }


    }                                        

    // Variables declaration - do not modify                     
    private javax.swing.JButton jButton1;
    private javax.swing.JTextField jTextField1;
    // End of variables declaration                   
}

И моя трассировка стека с сервера:

Exception in thread "Thread-0" java.lang.NullPointerException
    at testserverclient.ServerThread.run(ServerThread.java:39)

Строка 39:

if(textFromClient.equals("Quit"))

Ответы [ 2 ]

2 голосов
/ 24 марта 2012

Идея обработки сообщения о выходе хороша. Но ваш клиент никогда не отправляет такое сообщение о выходе. Это просто закрывает сокет. Это приводит к тому, что на другой стороне сокета (вашего сервера) BufferedReader возвращает null, когда вы запрашиваете следующую строку. Итак, чтобы решить эту проблему, убедитесь, что ваш клиент пишет сообщение о выходе, которое позволит серверу закрыть сокет в нужный момент и прекратить чтение из него. И чтобы быть уверенным, добавьте проверку возвращаемой строки на стороне сервера, если она пуста.

if (textFromClient == null || textFromClient.equals("Quit"))
{
     socket.close();
     break; // Break out of the reading loop.
}

Редактировать : И это для клиентской стороны:

if (txtFromClient.equals("Quit"))
{
    outToServer.println("Quit");
    outToServer.flush();
    outToServer.close();
}

Убедитесь, что вы не закрываете сокет в блоке finally. Закрывайте его только при отправке сообщения о выходе.


Совет : Вы можете создать PrintStream в режиме автоматической очистки:

PrintStream outToServer = new PrintStream(socket.getOutputStream, true);

При включении автоматического сброса он сбрасывается после каждого оператора печати (ln). Так что вам не нужно звонить каждый раз flush().

1 голос
/ 23 марта 2012

Когда BufferedReader.readLine() возвращает ноль, это означает, что больше нет данных для чтения.Вы в конце потока.(Обычно для сокетов это означает, что другой конец закрыл соединение.)

Конечно, null не является объектом, null.equals(anything) вызовет исключение.

Вы можете избежатьисключение, говоря что-то вроде

if (textFromClient == null || textFromClient.equals("Quit"))

, поскольку любое условие означает, что клиент завершил работу и соединение должно быть разорвано.

Что касается клиента ... закрытие потока, переданного вамSocket (как вы делаете в jButton1ActionPerformed), также закрывает Socket.Возможно, вы захотите сделать свои поля-члены для своих самых верхних потоков где-нибудь в вашем клиенте, чтобы вы могли удерживать их между вызовами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...