当前位置: 代码迷 >> J2SE >> 大神帮忙debug迷你版聊天工具!bug很严重!该怎么解决
  详细解决方案

大神帮忙debug迷你版聊天工具!bug很严重!该怎么解决

热度:116   发布时间:2016-04-23 19:45:23.0
大神帮忙debug迷你版聊天工具!bug很严重!
  楼主想写一个聊天工具,迷你版的,用java网络编程中运输层的tcp协议,为了接受信息,然后启动一个新线程,但是这个县城启动之后,就会是整个程序都死掉。你先启动服务端,然后再启动客户端。当客户端向服务端发送几条消息之后,客户度啊就会死掉。目前还不会使用eclipse的debug功能,大神帮忙debug,顺便可否说下debug过程?如何下断点或者如何发现bug等!

我用System.out.println();发现bug出现在,但是不知道具体是什么bug!!
服务端:

import java.net.*;
import java.io.*;

public class Server {
private ServerSocket ss = null;
private DataInputStream dis = null;

private void start() {

try{
ss = new ServerSocket(8888);
while(true) {
Socket s = ss.accept();
System.out.println("A Client is coming...");
new SocketThread(s).start();
}
} catch(IOException e) {
System.out.println("The port is used");
System.exit(0);
}
}

public static void main(String[] args) {
new Server().start();
}

//define a new thread, to hold a socket
private class SocketThread extends Thread {
private Socket s = null;
private DataInputStream dis = null;
private DataOutputStream dos = null;

public SocketThread(Socket s) {
this.s = s;

try {
dis = new DataInputStream(s.getInputStream());
dos = new DataOutputStream(s.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
}

@Override
public void run() {
boolean bConnected = true;
String str = null;
try {
while(bConnected) {
str = dis.readUTF().trim();
if("886#".equals(str)) {
System.out.println("A client is closing...");
break;
}
System.out.println(str);
send(str.trim());
}
} catch (IOException e) {
e.printStackTrace();
}

if(s != null) {
try {
s.close();
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

private void send(String m) {
try {
dos.writeUTF(m);
dos.flush();
System.out.println("Send to client:" + m);
} catch (IOException e) {
e.printStackTrace();
}
}
}

}


客户端:

import javax.swing.*;
import javax.swing.border.*;

import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;

public class ChatClient extends JFrame {

private JTextArea jtaRecoder = new JTextArea();
private JTextArea jtaMessage = new JTextArea();
private JButton jbt = new JButton("Send");

private Socket socket = null;
private DataOutputStream dos = null;
private DataInputStream dis = null;

public ChatClient() {

// 聊天记录框和消息发送面板的属性
jtaRecoder.setBackground(Color.YELLOW);
jtaMessage.setBackground(Color.ORANGE);
jtaRecoder.setBorder(new TitledBorder("chatRord:"));
jtaMessage.setBorder(new TitledBorder("message:"));
jtaMessage.setFont(new Font("", Font.BOLD, 15));
jtaRecoder.setFont(new Font("", Font.BOLD, 14));
jtaMessage.setWrapStyleWord(true);
jtaMessage.setLineWrap(true);
jtaRecoder.setWrapStyleWord(true);
jtaRecoder.setLineWrap(true);
jtaRecoder.setEditable(false);

// 布局设计
this.setLayout(new GridLayout(2, 1));
this.add(new JScrollPane(jtaRecoder));
JPanel message = new JPanel();
message.setLayout(new BorderLayout());
message.add(new JScrollPane(jtaMessage), BorderLayout.CENTER);
message.add(jbt, BorderLayout.EAST);
this.add(message);

this.setTitle("ChatClient");
this.setResizable(false);
this.setSize(500, 300);
this.setVisible(true);
this.setLocationRelativeTo(null);
this.addWindowListener(new WindowAdapter() {

@Override
public void windowClosing(WindowEvent arg0) {
disconnect();
System.exit(0);
}
});

connect();
jbt.addActionListener(new ButtonActionListener());
new RecevThread().start();
}

public void connect() {
try {
socket = new Socket("127.0.0.1", 8888);
dos = new DataOutputStream(socket.getOutputStream());
dis = new DataInputStream(socket.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}

}

public void disconnect() {
try {
dos.writeUTF("886#");
dos.flush();
} catch (IOException e) {
e.printStackTrace();
}

if(dos != null) {
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}

if(socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

private class ButtonActionListener implements ActionListener {

@Override
public void actionPerformed(ActionEvent arg0) {
String str = jtaMessage.getText().trim();
jtaRecoder.append("Me: " + str + "\n");
jtaMessage.setText("");

try {
dos.writeUTF(str);
dos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}

public static void main(String[] args) {
new ChatClient();
}

private class RecevThread extends Thread {

@Override
public void run() {
while(true) {
try {
String str = dis.readUTF().trim();
if("886#".equals(str)) {
ChatClient.this.disconnect();
break;
}
jtaRecoder.setText(jtaRecoder.getText() + "You: " + 
str + "\n");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

------解决思路----------------------
可以看看 log4j 之类的日志工具 
------解决思路----------------------
先跑了一下你的程序,发现客户端发送三次数据就崩了。。。。等我仔细研究研究。
------解决思路----------------------
引用:
我用System.out.println();发现bug在客户端的第130行。具体如何解决我也不知道。。。
用System.out.println();非常痛苦啊,但是用debug功能,怎么也不会找bug,还不如System.out.println()来的直接!

ClientChat的线程并不是死掉,而是阻塞了。客户端线程阻塞的原因你已经定位到了,是因为Client端代码的130行调用了SetTest方法,导致并发更新UI界面,RecevThread被AWT-EventQueue(Swing的UI事件分发线程)阻塞了。调试多线程问题时,可以使用JDK提供的JConsole查看线程信息,截图如下:
Swing的事件分发进程


RecevThread线程



另外,Swing编程时不要在另一个线程中直接更改UI控件,这样会导致多线程问题,可以用SwingUtilities.invokeLater方法将修改动作放到AWT-EventQueue线程中执行,示例如下:

private class RecevThread extends Thread {

@Override
public void run() {
while(true) {
try {
final String str = dis.readUTF().trim();
if("886#".equals(str)) {
ChatClient.this.disconnect();
break;
}

// jtaRecoder.setText(jtaRecoder.getText() + "You: " + 
// str + "\n");

SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
jtaRecoder.setText(jtaRecoder.getText() + "You: " + str + "\n");
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

附送官方教程一篇:http://docs.oracle.com/javase/tutorial/uiswing/concurrency/
------解决思路----------------------
我说调式半天没看出哪有毛病来,原来是我未接触到的层面,受教了。
------解决思路----------------------
是死锁了
出现这种情况是因为RecevThread 在 setText的时候,将AbstractDocument 里面的一个当前写入线程变量设置为了RecevThread,然后经过一系列调用以后,又需要ThreeLock 锁来继续下面的工作。
而这时候,TreeLock 的拥有者是AWT Thread. AWT 在执行到后面某一步的时候,需要确保 AbstractDocument 不在写入状态,而RecevThread 已经将AbstractDocument 设置为写入状态,因此AWT Thread 在循环休眠等待 写入状态清除,因此发生了死锁。
  相关解决方案