我现在开始在Daniel Liang的“Java编程简介”一书的帮助下学习Java网络API。出现的一个例子如下。这个想法是有一个服务器和一个客户端。客户端向服务器提交半径值,该服务器从中计算圆的一个区域并将其发送回客户端。但是,下面的代码(我仔细检查过)不起作用。
Client.java
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Client extends JFrame {
private JTextField jtf = new JTextField();
private JTextArea jta = new JTextArea();
private DataOutputStream toServer;
private DataInputStream fromServer;
public static void main(String[] args) {
new Client();
}
public Client()
{
//GUI
JPanel p = new JPanel();
p.setLayout(new BorderLayout());
p.add(new JLabel("Enter Radius"), BorderLayout.WEST);
p.add(jtf, BorderLayout.CENTER);
jtf.setHorizontalAlignment(JTextField.RIGHT);
setLayout(new BorderLayout());
add(p, BorderLayout.NORTH);
add(new JScrollPane(jta), BorderLayout.CENTER);
jtf.addActionListener(new TextFieldListener());
setTitle("Client");
setSize(500,300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
try {
Socket socket = new Socket("ip address of computer running server window", 8000);
fromServer = new DataInputStream(socket.getInputStream());
toServer = new DataOutputStream(socket.getOutputStream());
}
catch(IOException ex){
jta.append(ex.toString() + "\n");
}
}
private class TextFieldListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
try {
double radius = Double.parseDouble(jta.getText().trim());
toServer.writeDouble(radius);
toServer.flush();
double area = fromServer.readDouble();
jta.append("Radius is " + radius + "\n");
jta.append("The Area recieved from the server is " + area + "\n");
}
catch(IOException ex){
System.err.println(ex);
}
}
}
}
Server.java
import java.io.*;
import java.net.*;
import java.util.*;
import java.awt.*;
import javax.swing.*;
public class Server extends JFrame {
private JTextArea jta = new JTextArea();
public static void main(String[] args) {
new Server();
}
public Server()
{
//GUI
setLayout(new BorderLayout());
add(new JScrollPane(jta), BorderLayout.CENTER);
setTitle("Server");
setSize(500,300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
//Server Code
try {
ServerSocket serverSocket = new ServerSocket(8000);//Establish this server with the port 8000
jta.append("Server started at " + new Date() + "\n");
//Allows server to listen for connections
Socket socket = serverSocket.accept();
//Data streams for writing/reading data into the connected socket from above
DataInputStream inputFromClient = new DataInputStream(socket.getInputStream());
DataOutputStream outputToClient = new DataOutputStream(socket.getOutputStream());
while(true) {
double radius = inputFromClient.readDouble();
double area = radius * radius * Math.PI;
outputToClient.writeDouble(area);
jta.append("Radius recieved from client: " + radius + "\n");
jta.append("Area found: " + area + "\n");
}
}
catch(IOException ex){
System.err.println(ex);
}
}
}
但是,当我运行此代码并输入半径值时,我从客户端窗口收到以下错误消息:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at Client$TextFieldListener.actionPerformed(Client.java:51)
at javax.swing.JTextField.fireActionPerformed(JTextField.java:492)
at javax.swing.JTextField.postActionEvent(JTextField.java:705)
at javax.swing.JTextField$NotifyAction.actionPerformed(JTextField.java:820)
at javax.swing.SwingUtilities.notifyAction(SwingUtilities.java:1645)
at javax.swing.JComponent.processKeyBinding(JComponent.java:2859)
at javax.swing.JComponent.processKeyBindings(JComponent.java:2894)
at javax.swing.JComponent.processKeyEvent(JComponent.java:2822)
at java.awt.Component.processEvent(Component.java:6191)
at java.awt.Container.processEvent(Container.java:2084)
at java.awt.Component.dispatchEventImpl(Component.java:4776)
at java.awt.Container.dispatchEventImpl(Container.java:2142)
at java.awt.Component.dispatchEvent(Component.java:4604)
at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1856)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:722)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:1000)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:865)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:686)
at java.awt.Component.dispatchEventImpl(Component.java:4648)
at java.awt.Container.dispatchEventImpl(Container.java:2142)
at java.awt.Window.dispatchEventImpl(Window.java:2492)
at java.awt.Component.dispatchEvent(Component.java:4604)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:717)
at java.awt.EventQueue.access$400(EventQueue.java:82)
at java.awt.EventQueue$2.run(EventQueue.java:676)
at java.awt.EventQueue$2.run(EventQueue.java:674)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:86)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:690)
at java.awt.EventQueue$3.run(EventQueue.java:688)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:86)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:687)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
我该如何解决这个问题? 这是我从中得到的书的pdf链接。检查第33章,第1180页(pdf第1213页): http://ccis141.files.wordpress.com/2013/09/introduction-to-java-programming-comprehensive-9th-edition.pdf
答案 0 :(得分:2)
变量toServer
为null
。
在构造函数中初始化它时,JFrame
在初始化toServer
之前对用户可见。可能发生的情况是Client
实例无法建立与服务器的连接,并且new Socket("ip address of computer running server window", 8000)
被阻止,并最终会超时。
但是,UI已在运行,用户可以已经触发请求。
当与服务器的连接成功时,NPE不会发生,一切正常。
一个简单的测试就是移动线
setVisible(true);
到toServer
初始化之后,在这种情况下,只有在连接成功且toServer
不为空时才会显示客户端UI。
答案 1 :(得分:0)
就网络代码而言,我在这里看不出任何错误。与上述用户之一一样,实际情况是您的客户端由于某种原因未建立与您的服务器的连接,但仍允许用户提交请求。我怀疑它与你的TextFieldListener
有关。既然您提到这是您第一次使用Java学习网络,我建议您在没有花哨的GUI的情况下启动并使用命令行应用程序。通过这种方式,您可以更多地关注网络方面,而不必处理UI和事件处理(稍后您可以使它变得漂亮)。为此,我写了一个客户端的非GUI形式,它仍然可以与你现有的服务器一起使用(没有错)。
import java.net.*;
import java.io.*;
import java.util.*;
public class ConsoleClient {
Socket connectionSocket;
DataInputStream inputStream;
DataOutputStream outputStream;
Scanner input;
double radius;
public static void main(String[] args) {
new ConsoleClient();
}
public ConsoleClient()
{
input = new Scanner(System.in);
try
{
connectionSocket = new Socket("Server IP", 8000);
inputStream = new DataInputStream(connectionSocket.getInputStream());
outputStream = new DataOutputStream(connectionSocket.getOutputStream());
System.out.println("Connection established !");
System.out.println("Please enter a radius: ");
radius = input.nextDouble();
outputStream.writeDouble(radius);
outputStream.flush();
System.out.println("Data from Client send !");
System.out.println("The area received is " + inputStream.readDouble());
}
catch(Exception ex)
{
System.out.println(ex + "");
}
}
}