我是java的新手,我尝试用TCP Socket编写一个简单的客户端服务器但是经过几天的努力我遇到了麻烦,我无法解决这个问题。
我使用BufferReader.Readline();
获得了null我的服务器代码:
启动服务器代码
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循环中)但它收到null,我不知道在这种情况
我的客户代码:
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"))
答案 0 :(得分:2)
处理退出消息的想法很好。但是你的客户从不发送这样的退出消息。它只是关闭套接字。这会导致套接字(您的服务器)的另一端在您询问下一行时BufferedReader返回null。因此,要解决此问题,请确保您的客户端写入退出消息,这将允许服务器在正确的时刻关闭套接字并停止从中读取。并且非常确定,如果返回的String为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);
启用自动刷新时,它会在每个print(ln)语句后刷新。因此,您不必每次都致电flush()
。
答案 1 :(得分:1)
当BufferedReader.readLine()
返回null时,表示没有更多数据可供读取。你在流的最后。 (通常使用套接字,这意味着另一端关闭了连接。)
当然,null
不是对象,null.equals(anything)
会抛出异常。
您可以通过说
之类的内容来避免异常if (textFromClient == null || textFromClient.equals("Quit"))
因为任何一个条件都意味着客户端已完成,连接应该终止。
至于客户端......关闭一个Socket给你的流(正如你在jButton1ActionPerformed
中所做的那样),也关闭了Socket。您可能希望在客户端的某个位置创建最顶层的流成员字段,这样您就可以在调用之间保留它们。