这是基本聊天服务器的代码。要求用户在Chat_Client上输入用户名和密码,然后使用EncryptedMessage的加密方法对其进行加密,并使用writeObject通过ClientOutputStream将其发送到Chat_Server。
当运行代码行clientOutputStream.writeObject(uname)时,它返回nullPointerException。我可以在这行代码之前输出加密的用户名,但不能在之后输出。这是为什么?
Chat_Client
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
EncryptedMessage
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);
答案 0 :(得分:1)
为什么会这样?
如果你在该行上获得NullPointerException
,则只有一种可能的解释。那就是clientOutputStream
是null
。
由于uname
的值,未发生异常。传递null
的行为不会,也不能 1 抛出NullPointerException
。实际上,将null
写入ObjectOutputStream
。
接下来的步骤应该是:
确认此时clientOutputStream
null
,然后
找出原因null
。
您的代码太长了,无法通过目视检查&#34;进行调试,但看起来应该在getConnections()
中调用main(...)
时设置该字段。也许我错过了一些东西......
1 - 有一个边缘情况,您在方法需要基元类型的上下文中传递null
而不是盒装基元类型。在这种情况下,拆箱将抛出NullPointerException
。 看起来像一个NPE正在被调用的行为中被抛出,但实际上它发生在隐藏的拆箱操作中。功能
答案 1 :(得分:0)
ObjectOutStream可能为null。要验证是否是这种情况,请在调用任何方法之前将其记录到控制台。刚刚在sendLoginDetails方法中尝试put
System.out.println(clientOutputStream);
如果clientOutputStream为null,它将打印null。