java - writeObject 到 OutputStream 后出现空指针异常

标签 java encryption

这是基本聊天服务器的代码。用户被要求在 Chat_Client 上输入用户名和密码,然后使用 EncryptedMessage 的加密方法对其进行加密,并使用 writeObject 通过 ClientOutputStream 发送到 Chat_Server。

当代码行 clientOutputStream.writeObject(uname) 运行时,它返回 nullPointerException。我可以在这行代码之前输出加密的用户名,但不能在之后输出。这是为什么?

聊天客户端

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.net.*;
import javax.swing.text.*;
public class Chat_Client extends JFrame
{   // socket to communicate with server
    Socket mySocket;
    // input stream - data sent by the server will be read from this stream
    ObjectInputStream clientInputStream;
    // output stream - data sent to the server will be written to this stream
    ObjectOutputStream clientOutputStream;

    // variables for the GUI components of the game
    Container c;
    ButtonHandler bHandler;
    NameButtonHandler nbHandler;
    ImageButtonHandler ibHandler;
    JButton sendButton, logonButton;
    JButton[] nameButtons, imageButtons;
    ImageIcon[] images = {new ImageIcon("smile.gif"), new ImageIcon("frown.gif"), new ImageIcon("wink.gif"), new ImageIcon("eek.gif"), new ImageIcon("confused.gif"), new ImageIcon("embarrassed.gif"), new ImageIcon("stop.gif")};
    JPasswordField password;
    JTextField username;
    JTextPane outputArea,inputArea;
    StyledDocument docInputArea, docOutputArea;
    Style style;
    JPanel namesPanel, imageButtonsPanel, nameButtonsPanel, sendButtonPanel, inputAreaPanel, logonFieldsPanel, logonButtonPanel, leftPanel, rightPanel, cCenterPanel, lowerPanel, outputAreaPanel;
    JLabel namesLabel, usernameLabel, passwordLabel, imageLabel;

    String[] names = {"Arken", "Ben", "Darklark", "Free"};

    //everybody offline to start with
    boolean[] loggedOn = {false, false, false, false};
    String recipients = "";

    public Chat_Client()
    {   super("Chat_Client");
        addWindowListener
        (   new WindowAdapter()
            {   public void windowClosing(WindowEvent e)
                {   System.exit(0);
                }
            }
        );

        // create and add GUI components
        c = getContentPane();
        c.setLayout(new BorderLayout());

        // GUI components for the username
        logonFieldsPanel = new JPanel();
        logonFieldsPanel.setLayout(new GridLayout(2,2,5,5));
        usernameLabel = new JLabel("Enter Username: ");
        logonFieldsPanel.add(usernameLabel);
        username = new JTextField(10);
        logonFieldsPanel.add(username);

        // GUI components for the password
        passwordLabel = new JLabel("Enter Password: ");
        logonFieldsPanel.add(passwordLabel);
        password = new JPasswordField(10);
        logonFieldsPanel.add(password);
        c.add(logonFieldsPanel,BorderLayout.CENTER);

        // panel for the logon button
        logonButtonPanel = new JPanel();
        logonButton = new JButton("logon");
        bHandler = new ButtonHandler();
        logonButton.addActionListener(bHandler);
        logonButtonPanel.add(logonButton);
        c.add(logonButtonPanel, BorderLayout.SOUTH);

        setSize(300,125);
        setResizable(false);
        setVisible(true);
    }


    void setUpChatClient(boolean chatting)
    {   // remove iniial GUI components (textfield, password field, logon button)
        c.remove(logonButtonPanel);
        c.remove(logonFieldsPanel);

        if(!chatting)
            // if the user has not logged on an error message will be displayed
            c.add(new JTextArea("Logon unsuccessful"));
        else
        {   // if the user has logged on the message service GUI will be set up
            c.setLayout(new BorderLayout());
            leftPanel = new JPanel(new GridLayout(2,1));
            leftPanel.setBackground(Color.WHITE);
            rightPanel = new JPanel(new GridLayout(2,1));

            imageLabel = new JLabel(new ImageIcon("people1.jpg"));
            imageLabel.setBackground(Color.WHITE);
            leftPanel.add(imageLabel);

            // name buttons enable user to choose message recipient(s)
            nameButtonsPanel = new JPanel(new GridLayout(5,1));
            nameButtons = new JButton[names.length];
            nbHandler = new NameButtonHandler();
            for(int r = 0; r < nameButtons.length; r++)
            {   nameButtons[r] = new JButton(names[r]);
                nameButtons[r].addActionListener(nbHandler);
                nameButtons[r].setEnabled(loggedOn[r]);
                nameButtonsPanel.add(nameButtons[r]);
            }
            leftPanel.add(nameButtonsPanel);

            outputAreaPanel = new JPanel();
            outputAreaPanel.setBackground(Color.WHITE);
            // messages from the server will be displayed in this JTextPane
            outputArea = new JTextPane();
            outputArea.setEditable(false);
            Dimension d = new Dimension(300,150);
            outputArea.setPreferredSize(d);
            docOutputArea = (StyledDocument) outputArea.getDocument();
            style = docOutputArea.addStyle("StyleName", null);
            JScrollPane outputScrollPane = new JScrollPane(outputArea);
            outputAreaPanel.add(outputScrollPane);
            rightPanel.add(outputAreaPanel);

            inputAreaPanel = new JPanel();
            inputAreaPanel.setBackground(Color.WHITE);
            // image buttons enable user to add an image to a text message
            imageButtonsPanel = new JPanel();
            imageButtonsPanel.setBackground(Color.WHITE);
            d = new Dimension(25,25);
            ibHandler = new ImageButtonHandler();
            imageButtons = new JButton[images.length];
            for(int j = 0; j < imageButtons.length; j++)
            {   imageButtons[j] = new JButton(images[j]);
                imageButtons[j].setPreferredSize(d);
                imageButtons[j].setBorderPainted(false);
                imageButtons[j].addActionListener(ibHandler);
                imageButtonsPanel.add(imageButtons[j]);
            }
            inputAreaPanel.add(imageButtonsPanel);

            d = new Dimension(300,60);
            // text messages will be entered into this JTextPane
            inputArea = new JTextPane();
            inputArea.setPreferredSize(d);
            docInputArea = (StyledDocument) inputArea.getDocument();
            style = docInputArea.addStyle("StyleName", null);
            JScrollPane scrollPane = new JScrollPane(inputArea);
            inputAreaPanel.add(scrollPane);

            // the send button enables user to send a text message
            sendButtonPanel = new JPanel();
            sendButtonPanel.setBackground(Color.WHITE);
            bHandler = new ButtonHandler();
            sendButton = new JButton("send");
            sendButton.addActionListener(bHandler);
            sendButtonPanel.add(sendButton);
            inputAreaPanel.add(sendButtonPanel);
            rightPanel.add(inputAreaPanel);

            c.add(rightPanel, BorderLayout.CENTER);
            c.add(leftPanel, BorderLayout.WEST);
            setSize(425, 375);
        }
        setResizable(false);
        setVisible(true);
    }

    void changeNameButton(int i, Color c)
    {   /* change the colour of the text on a name 
           button - red indicates that this friend
           is a recipient of next message */
        nameButtons[i].setForeground(c);
    }

    void changeNameButtons(Color c)
    {   /* change the colour of the text on all the 
           name buttons */
        for(int r = 0; r < nameButtons.length; r++)
           changeNameButton(r, c);
    }

    void changeNameButtons()
    {   /* disable or enable each name button - a
           button is enabled if that friend is online,
           otherwise it is disabled */
        for(int r=0; r<nameButtons.length; r++)
        {
            //if user is logged on
            if(loggedOn[r] == true)
            {
                //enable the name button
                nameButtons[r].setEnabled(true);
            }
            else
            {
                nameButtons[r].setEnabled(false);
            }
        }//end of for loop
    }

    void changeFriends(String n, boolean b)
    {   // change a friend's "online" status
        //for loop to iterate through names
        for(int r=0; r < names.length; r++)
        {
            //if loggedOn is true, set boolean to true
            if(n.equals(names[r]))
            {
                loggedOn[r] = b;
            }
        }//end of for loop

        // call method to update buttons
        changeNameButtons();
    }

    void addOutput(String str)
    {   /* this will split the message string into words using the space
           character as a delimiter, the words will be stored in consecutive 
           elements of array "words" */
        String[] words = str.split(" \\s*");
        try
        {   // travese array, taking each word in turn
            for(int i = 0; i < words.length; i++)
            {   /* if the first character of this word is $ this indicates that
                    this string represents an image in the text message */
                if(words[i].charAt(0) == '$')
                {   /* the remainder of this word will be a number indicating the 
                       array element in which the image is stored - retrieve this 
                       number from the string */
                    String position = words[i].substring(1, words[i].length());
                    // cast this string number to an int value 
                    int pos = Integer.parseInt(position);
                    // retrieve the appropriate image from the array
                    StyleConstants.setIcon(style, images[pos]);
                    // add the image to the text output area
                    docOutputArea.insertString(docOutputArea.getLength(), " $" + pos + " ", style);
                }
                else
                    // otherwise add the next text word to the text output area
                    docOutputArea.insertString(docOutputArea.getLength(), words[i] + " ", null);
            }
            // add a newline character to the text output area
            docOutputArea.insertString(docOutputArea.getLength(), " \n", null);
            // set the caret position in the text output area
            outputArea.setCaretPosition(docOutputArea.getLength());
        }
        catch(BadLocationException ee)
        {   System.out.println(ee);
            System.exit(1);
        }
    }

    void closeChatClient()
    {   // user has quit the message service - disable GUI components
        // disable send message button
        sendButton.setEnabled(false);

        // disable all name buttons
        for(int r=0; r<names.length; r++)
        {
            nameButtons[r].setEnabled(false);
        }

        // disable all image buttons
        for(int s=0; s<imageButtons.length; s++)
        {
            imageButtons[s].setEnabled(false);
        }

        // set input area to prevent text entry
        inputArea.setEditable(false);
    }

    void sendLoginDetails()
    {   
        try
        {   
            // get username from text field and encrypt
            EncryptedMessage uname = new EncryptedMessage(username.getText());
            uname.encrypt();

            // get password from password field and encrypt
            EncryptedMessage pword = new EncryptedMessage(new String (password.getPassword()));
            pword.encrypt();

            System.out.println("1 " + uname);
            // send encrypted username and password to server
            clientOutputStream.writeObject(uname);
            System.out.println("2 " + uname);
            clientOutputStream.writeObject(pword);                                  

        }
        catch(IOException e) // thrown by methods writeObject
        {   System.out.println(e);
            System.exit(1);
        }           
    }

    void getConnections()
    {   try
        {   // initialise a socket and get a connection to server
        //server using post 7500
            mySocket = new Socket(InetAddress.getLocalHost(), 7500);

            // get input & output object streams
            clientInputStream = new ObjectInputStream(mySocket.getInputStream());
            clientOutputStream = new ObjectOutputStream(mySocket.getOutputStream());

            /* create a new thread of Chat_ClientThread, sending input
               stream variable as a parameter */
            Chat_ClientThread newThread = new Chat_ClientThread(clientInputStream);

            // start thread - execution will begin at method run
            newThread.start();
        }
        catch(UnknownHostException e) // thrown by method getLocalHost
        {   System.out.println(e);
            System.exit(1);
        }
        catch(IOException e) // thrown by methods ObjectOutputStream, ObjectInputStream
        {   System.out.println(e);
            System.exit(1);
        }
    }

    void sendMessage(String str)
    {   try
        {   /* if you have not chosen any recipients this message will be 
               sent to all friends by default */
            if(recipients.equals(""))
                recipients = names[names.length - 1] + ",";

            // separate recipients and the message by inserting # character  
            str = recipients + "#" + str;
            // compress message
            CompressedMessage cm = new CompressedMessage(str);
            cm.compress();
            // send message to server
            clientOutputStream.writeObject(cm);
            // clear recipients for next message
            recipients = "";
            // clear the input area
            inputArea.setText("");
            // change the colour of text on name buttons of friends online
            changeNameButtons(Color.BLACK);
        }
        catch(IOException e) // thrown by method writeObject
        {   System.out.println(e);
            System.exit(1);
        }
    }

    void closeStreams()
    {   
        try{
            clientInputStream.close();
            clientOutputStream.close();

            //close socket-good practice
            mySocket.close();
        }

        catch(IOException e) // thrown by method close
        {   System.out.println(e);
            System.exit(1);
        }
    }

    public static void main(String args[])
    {   Chat_Client gameClient = new Chat_Client();
        gameClient.getConnections();
    }


    private class Chat_ClientThread extends Thread
    {   ObjectInputStream threadInputStream;

        public Chat_ClientThread(ObjectInputStream in)
        {   // initialise input stream
            threadInputStream = in;
        }

        // when method start() is called thread execution will begin in this method
        public void run()
        {   try
            {   
                boolean chatting = (Boolean)threadInputStream.readObject();
                // call method to change the client GUI
                setUpChatClient(chatting);
                if(!chatting)
                    // call method to close input & output streams & socket
                    closeStreams();
                else
                {   // this loop will continue until this client quits the chat service
                    while(chatting)
                    {   // read next compressed message from server
                        CompressedMessage nextMsg = (CompressedMessage)clientInputStream.readObject();

                        // decompressed message
                        nextMsg.decompress();

                        // retrieve decompressed message
                        String message = nextMsg.getMessage();

                        // if this client has quit the server will send this last message
                        if(message.equals("goodbye"))
                        {   // chatClient should be closed
                            //call method made above
                            closeChatClient();

                            // close input & output streams & socket
                            closeStreams();

                            // no more chatting - use boolean as above
                            chatting = false;
                        }
                        else
                        {   if(message.substring(0,4).equals("join"))
                            {  
                                changeFriends(message.substring(4,message.length()), true);
                                // output message in output area
                                addOutput(message.substring(4,message.length()) + " has joined");
                            }
                            else
                            {   if(message.substring(0,4).equals("quit"))
                                {  
                                    changeFriends(message.substring(4,message.length()), false);
                                    // output message in output area
                                    addOutput(message.substring(4,message.length()) + " has quit");
                                }
                                else
                                {   if(message.substring(0,6).equals("online"))
                                    {   /* if the first word in the message is "online" then this client
                                           has just joined the chat service and this message lists
                                           the names of all other friends that are online */
                                        // split string to separate names of friends online
                                        String[] online = message.substring(6,message.length()).split(",\\s*");
                                        if(!online[0].equals("none"))
                                        {   for(int i = 0; i < online.length; i++)
                                                changeFriends(online[i], true);
                                        }
                                        // output message in output area
                                        addOutput("Your friends online : " + message.substring(6,message.length()-1));
                                    }
                                    else
                                        // output message in output area
                                        addOutput(message);
                                } // end else
                            } // end else
                        } // end else
                    } // end while
                } // end else
            } // end try
            catch(IOException e) // thrown by method readObject
            {   System.out.println(e);
                System.exit(1);
            }
            catch(ClassNotFoundException e) // thrown by method readObject
            {   System.out.println(e);
                System.exit(1);
            }
        } // end method run
    } // end of class Chat_ClientThread

    private class NameButtonHandler implements ActionListener
    {  
        public void actionPerformed(ActionEvent e)
        {   int pos = -1;
            // loop to identify which of the name buttons were clicked
            for(int r = 0; r < nameButtons.length; r++)
            {   if(e.getSource() == nameButtons[r])
                    pos = r;
            }
            // add this friend's name to recipients list
            recipients += names[pos] + ",";
            if(pos == names.length - 1)
               /* you have chosen to send the message to all 
                  friends - change the colour of all the name buttons */
               changeNameButtons(Color.RED);
            else
                /* you have chosen to send the message to an individual 
                   friend - change the colour of this friends name button */
                changeNameButton(pos, Color.RED);
            }
    }  // end of class NameButtonHandler

    private class ImageButtonHandler implements ActionListener
    {   // if any of the image buttons are clicked execution will continue in this method
        public void actionPerformed(ActionEvent e)
        {   int pos = -1; 
            // loop to identify which of the buttons were clicked
            for(int r = 0; r < imageButtons.length; r++)
            {   if(e.getSource() == imageButtons[r])
                    pos = r;
            }
            try
            {   // retrieve the appropriate image from the array
                StyleConstants.setIcon(style, images[pos]);
                // add the image to the text input area
                docInputArea.insertString(docInputArea.getLength(), " $" + pos + " ", style);
            }
            catch(BadLocationException ee)
            {   System.out.println(ee);
                System.exit(1);
            }
        }
    }  // end of class ImageButtonHandler

    private class ButtonHandler implements ActionListener
    {   // if the logon or send buttons are clicked execution will continue in this method
        public void actionPerformed(ActionEvent e)
        {   if(e.getSource() == logonButton)
                /* if the logon button is clicked call method to 
                   send the login details to the server */
                sendLoginDetails();
            else
            {   if(e.getSource() == sendButton)
                    /* if the send button is clicked call method to 
                       send the message to the server */
                    sendMessage(inputArea.getText());
            }
        }
    }  // end of class ButtonHandler
} // end of class Chat_Client

加密消息

import java.io.Serializable;

public class EncryptedMessage implements Serializable
{   // this instance variable will store the original, encrypted and decrypted message
    private String message;

    // this variable stores the key
    static String KEY = "cable"; 

    public EncryptedMessage(String message)
    {   // initialise original message
        this.message = message;
    }

    public String getMessage()
    {   // return (encrypted or decrypted) message
        return message;
    }

    public void encrypt()
    {   /* this variable stores the letters of the alphabet (in order) as a
       string - this string will be used to encrypt text */         
    String charSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,?0123456789 ";
        String cipherText = "";

        for(int i = 0; i < message.length(); i++)
        {   // find position of plaintext character in the character set
            int plainTxtCh = charSet.indexOf(message.charAt(i));

                // get position of next key character
            int keyPos = i % KEY.length();
                // find position of key character in the character set
                int keyCh = charSet.indexOf(KEY.charAt(keyPos));

            /* add key character to plaintext character - this shifts the
               plaintext character - then divide by length of
               character reference set and get remainder to wrap around */
            int cipherTxtCh = (plainTxtCh + keyCh) % charSet.length();
            /* get character at corresponding position in character reference
               set and add to cipherText */
            char c = charSet.charAt(cipherTxtCh);
            cipherText += c;
        }
        message = cipherText;
    }

    public void decrypt()
    {   /* this variable stores the letters of the alphabet (in order) as a
       string - this string will be used to decrypt text */
        //Must be able to handle numbers, punctuation marks - comma, full stop and questionmark
        String charSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.,?0123456789 ";
        String plainText = "";

        for(int i = 0; i < message.length(); i++)
        {   // find position of ciphertext character
            int cipherTxtCh = charSet.indexOf(message.charAt(i));

                // get position of next key character
            int keyPos = i % KEY.length();
                // find position of key character in the character set
                int keyCh = charSet.indexOf(KEY.charAt(keyPos));

            /* subtract original shift from character reference set length to
               get new shift, add shift to ciphertext character then
               divide by character reference set length and get remainder to
               wrap around */
            int plainTxtCh = (cipherTxtCh + (charSet.length() - keyCh)) % charSet.length();

            /* get character at corresponding position in character reference
               set and add to plainText */
            char c = charSet.charAt(plainTxtCh);
            plainText += c;
        }
        message = plainText;
    }
}

控制台出错

  1 EncryptedMessage@13b91982
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at Chat_Client.sendLoginDetails(Chat_Client.java:294)
    at Chat_Client$ButtonHandler.actionPerformed(Chat_Client.java:527)
    at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
    at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
    at java.awt.Component.processMouseEvent(Unknown Source)
    at javax.swing.JComponent.processMouseEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$400(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

聊天客户端中错误指向的第 294 行是

clientOutputStream.writeObject(uname);

最佳答案

Why is this?

如果您在该行收到 NullPointerException,则只有一种可能的解释。也就是说 clientOutputStreamnull

由于 uname 的值,异常没有发生。传递 null 的行为不会也不可能1抛出 NullPointerException。事实上,将 null 写入 ObjectOutputStream 是完全有效的。

您的下一步应该是:

  1. 确认此时 clientOutputStream null,然后,

  2. 找出为什么它是null

您的代码对于“通过目视检查进行调试”来说太长了,但看起来应该在 main(...)< 中调用 getConnections() 时设置该字段。也许我错过了一些东西......

<小时/>

1 - 有一种边缘情况,您在方法需要基元类型的上下文中传递 null 而不是装箱基元类型。在这种情况下,拆箱将抛出 NullPointerException。 看起来 NPE 是在调用过程中被抛出的,但实际上它是在隐藏的拆箱操作中发生的。

关于java - writeObject 到 OutputStream 后出现空指针异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27262009/

相关文章:

java - 如何使用 Java Swing 编写肮脏的丰富渐变边框

java - Elasticsearch 中关闭和关闭节点的区别?

c# - 使用 RSA 公钥解密使用 RSA 私钥加密的字符串

java - Java 中的凯撒密码(西类牙语字符)

java - Delphi SetBit-函数和TBitRange-Java中的类型

java - 如何使用 Java Google Drive API 上传文件

java - 这个java类线程安全吗?

java - 如何在 JUnit 测试初始化​​时模拟 Bean 所需的文件

php - 敏感数据是否应该通过脚本和数据库两种方式加密?

java - 通过 JDK 7 使用 AES 128 时出现问题