现象:按下注册后程序阻塞。尝试测试程序运行到何处,结果如下:
before accept
before send socket
after accept
after send socket
before read from client
----程序阻赛在服务器向客户端读取数据前。以下为代码,希望大家指点,谢谢。服务端:
package server;import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import client.Register;
import command.Command;
import config.Config;public class Server extends Thread {
private ServerSocket serverSocket; private Socket socket; private ObjectInputStream streamFromClient; private ObjectOutputStream streamToClient; public void run() {
try {
while (true) {
System.out.println("before accept");//
socket = serverSocket.accept();
System.out.println("after accept");//
streamFromClient = new ObjectInputStream(socket
.getInputStream());
System.out.println("before read from client");//
Command command = (Command) streamFromClient.readObject();
streamFromClient.close();
System.out.println("after read from client");//
streamToClient = new ObjectOutputStream(socket
.getOutputStream());
System.out.println("before write to client");//
streamToClient.writeObject(command.execute());
streamToClient.close();
System.out.println("after write to client");//
}
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
} } public Server() {
try {
serverSocket = new ServerSocket(Config.getRegisterProt());
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
} public static void main(String[] args) { new Server().start();
new Register();
}
}
客户端:
package client;import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextArea;
import javax.swing.JTextField;import command.RegisterCommand;import config.Config;public class Register extends JFrame { private JPanel panel = new JPanel(); private JLabel IDLabel = new JLabel("ID"); private JLabel nickNameLabel = new JLabel("昵称"); private JLabel passwordLabel = new JLabel("密码"); private JLabel rePasswordLabel = new JLabel("确认密码"); private JTextField IDField = new JTextField(20); private JTextField nickNameField = new JTextField(20); private JTextArea stateField = new JTextArea(3, 20); private JPasswordField passwordField = new JPasswordField(20); private JPasswordField rePasswordField = new JPasswordField(20); private JButton registerButton = new JButton("注册"); private JButton closeButton = new JButton("关闭"); private void deployComponent() {
this.getContentPane().add(panel);
this.setTitle("用户注册");
panel.setLayout(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
constraints.gridx = 0;
constraints.gridy = 0;
panel.add(IDLabel, constraints);
constraints.gridx = 1;
constraints.gridy = 0;
panel.add(IDField, constraints);
constraints.gridx = 0;
constraints.gridy = 1;
panel.add(nickNameLabel, constraints);
constraints.gridx = 1;
constraints.gridy = 1;
panel.add(nickNameField, constraints);
constraints.gridx = 0;
constraints.gridy = 2;
panel.add(passwordLabel, constraints);
constraints.gridx = 1;
constraints.gridy = 2;
panel.add(passwordField, constraints);
constraints.gridx = 0;
constraints.gridy = 3;
panel.add(rePasswordLabel, constraints);
constraints.gridx = 1;
constraints.gridy = 3;
panel.add(rePasswordField, constraints);
constraints.gridx = 0;
constraints.gridy = 4;
panel.add(registerButton, constraints);
constraints.gridx = 1;
constraints.gridy = 4;
stateField.setEditable(false);
stateField.setLineWrap(true);
panel.add(stateField, constraints);
constraints.gridx = 0;
constraints.gridy = 5;
panel.add(closeButton, constraints);
this.setSize(500, 300);
this.setVisible(true);
} private void deployAction() {
registerButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
try {
StringBuffer sb = new StringBuffer();
System.out.println("before send socket");//
Socket socket = new Socket(Config.getServer(), Config
.getRegisterProt());
System.out.println("after send socket");//
ObjectOutputStream toServer = new ObjectOutputStream(socket
.getOutputStream());
ObjectInputStream fromServer = new ObjectInputStream(socket
.getInputStream());
System.out.println("before write to server");//
toServer.writeObject(new RegisterCommand(IDField.getText(),
new String(passwordField.getPassword()),
new String(rePasswordField.getPassword()),
nickNameField.getText()));
toServer.close();
System.out.println("after write to server");//
System.out.println("before read from server");//
List message = (List) fromServer.readObject();
fromServer.close();
System.out.println("after read from server");//
if (((Boolean) message.get(0)).booleanValue())
stateField.setText("注册成功");
else {
for (int i = 1; i < message.size(); i++) {
sb.append(message.get(i));
if (i != message.size())
sb.append(";");
else
sb.append("。");
stateField.setText(sb.toString());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
closeButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) {
Register.this.dispose();
} });
} public Register() {
deployComponent();
deployAction();
} public static void main(String[] args) {
new Register();
}
}

解决方案 »

  1.   

    ObjectOutputStream创建时会有数据输出,而且ObjectOutputStream是有缓存的。
    如果同时要创建ObjectInputStream的话,最好要按照下面的顺序(Server和Client都一样)ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
    out.flush();
    ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
    ...否则就有可能某一方的ObjectInputStream在创建时因无法接收到ObjectOutputStream的初始数据而堵塞。
      

  2.   

    支持2楼的,ObjectOutputStream是由缓存的,建议使用后将其flush掉