关于java聊天室,求助

问题:
服务器端退出,线程却还在运行
报错:

java.net.SocketException: Socket closed

at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:152)
at java.net.SocketInputStream.read(SocketInputStream.java:122)
at java.net.SocketInputStream.read(SocketInputStream.java:210)
at java.io.DataInputStream.readUnsignedShort(DataInputStream.java:337)
at java.io.DataInputStream.readUTF(DataInputStream.java:589)
at java.io.DataInputStream.readUTF(DataInputStream.java:564)
at talkingRoom.Servicer$1.run(Servicer.java:127)

*********客户端************************
import java.awt.*;
import java.net.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;

@SuppressWarnings("serial")
public class Desktop extends JFrame implements ActionListener {
@SuppressWarnings("unused")
private class WindowCloser extends WindowAdapter {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
}

private Socket cs = null;
private JPanel p = new JPanel();
private JTextArea output = new JTextArea();
private JTextField input = new JTextField();
private DataOutputStream dos;
private DataInputStream dis;
private JButton b1 = new JButton("进入");
private JButton b2 = new JButton("退出");
private JLabel fuwuqis = new JLabel("服务器:");
private JTextField fuwuqi = new JTextField("127.0.0.1");
private JLabel duankous = new JLabel("端口:");
private JTextField duankou = new JTextField("8888");
private JLabel nichengs = new JLabel("昵称:");
private JTextField nicheng = new JTextField("游客1");
private JButton b3 = new JButton("发送");
private String talking;
private boolean started = false;
private boolean bConnected = false;
//UI界面(不需要再修改)
Desktop() {
    p.setLayout(new BorderLayout());
    JPanel p1 = new JPanel();
    JPanel p2 = new JPanel();
    p1.add(b1);
    b1.addActionListener(this);
    p1.add(b2);
    b2.addActionListener(this);
    p1.add(fuwuqis);
    p1.add(fuwuqi);
    p1.add(duankous);
    p1.add(duankou);
    p1.add(nichengs);
    p1.add(nicheng);
    p2.setLayout(new BorderLayout());
    p2.add(input, BorderLayout.CENTER);
    p2.add(b3, BorderLayout.EAST);
    b3.addActionListener(this);
    p.add(p1, BorderLayout.NORTH);
    p.add(p2, BorderLayout.SOUTH);
    p.add(output, BorderLayout.CENTER);
    buttonclose();
    this.setTitle("聊天室for客户端");
    this.add(p);
    this.setSize(500, 300);
    this.setVisible(true);
}
public void buttonclose() {
    b1.setEnabled(true);
    b2.setEnabled(false);
    b3.setEnabled(false);
    input.setEditable(false);
    fuwuqi.setEditable(true);
    duankou.setEditable(true);
    nicheng.setEditable(true);
}
public void buttonopen() {
    b1.setEnabled(false);
    b2.setEnabled(true);
    b3.setEnabled(true);
    input.setEditable(true);
    fuwuqi.setEditable(false);
    duankou.setEditable(false);
    nicheng.setEditable(false);
}

//连接函数,流与Socket所在
public void connect() {
    try {
        cs = new Socket(fuwuqi.getText(), Integer.parseInt(duankou.getText()));
        System.out.print("加入连接");
        dos = new DataOutputStream(cs.getOutputStream());
    } catch (UnknownHostException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
//断开函数,流与Socket所在
public void disconnect() {
    try {
        bConnected = false;
        dos.writeUTF("$%$");
        dis.close();
        dos.close();
        System.out.println("disdos.close");
        cs.close();
        System.out.println("cs.close");
        output.append("退出成功\n");
        buttonclose();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
//发送流函数
public void send() {
    try {
        if(talking == null) {
            dos.writeUTF("");
        }else {
            dos.writeUTF(talking);
        }
        dos.flush();
    } catch (IOException e1) {
        e1.printStackTrace();
    }
}
//接收流函数
public void receive() {
    try {
        started = true;
        bConnected = true;
        dis = new DataInputStream(cs.getInputStream());
        new Thread() {
            public void run() {
                System.out.println("开始接收");
                while (bConnected) {
                    String talking = "";
                    try {
                        talking = dis.readUTF();                            
                        output.append("\n\r" + "主机" + " : " + talking);
                        if("$%$".equalsIgnoreCase(talking)){
                            disconnect();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

// try {
// dis.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
}
}.start();
} catch (IOException e1) {
e1.printStackTrace();
}
}

public void actionPerformed(ActionEvent e) {
    String S = e.getActionCommand();
    if ("发送".equalsIgnoreCase(S)) {
        talking = input.getText().trim();
        String snicheng = nicheng.getText().trim();
        output.append("\n\r" + snicheng + " : " + talking);
        input.setText("");
        try {
            dos.writeUTF(snicheng);
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        send();
    } else if ("进入".equalsIgnoreCase(S)) {
        connect();
        receive();
        output.append("进入成功\n 服务器:" + fuwuqi.getText() + "\t端口:" + duankou.getText() + "\t昵称:" + nicheng.getText() + "\n");
        buttonopen();
    } else if ("退出".equalsIgnoreCase(S)) {
        disconnect();
    }
}

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

}
***********服务器********************************
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.swing.*;

@SuppressWarnings("serial")
public class Servicer extends JFrame implements ActionListener {
@SuppressWarnings("unused")
private class WindowCloser extends WindowAdapter {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
}

private ServerSocket ss = null;
private Socket s;
private JPanel p = new JPanel();
private JTextArea output = new JTextArea();
private JTextField input = new JTextField();
private DataOutputStream dos;
private DataInputStream dis;
private JButton b1 = new JButton("启动");
private JButton b2 = new JButton("退出");
private JButton b3 = new JButton("发送");
private String talking, nicheng;
private boolean started = true;
private boolean bConnected = false;

// UI界面(不需要再修改)
Servicer() {
    p.setLayout(new BorderLayout());
    JPanel p1 = new JPanel();
    JPanel p2 = new JPanel();
    p1.add(b1);
    b1.addActionListener(this);
    p1.add(b2);
    b2.addActionListener(this);
    b3.addActionListener(this);
    p2.setLayout(new BorderLayout());
    p2.add(input, BorderLayout.CENTER);
    p2.add(b3, BorderLayout.EAST);
    p.add(p1, BorderLayout.NORTH);
    p.add(p2, BorderLayout.SOUTH);
    p.add(output, BorderLayout.CENTER);
    b2.setEnabled(false);
    b1.setEnabled(true);
    b3.setEnabled(false);
    input.setEditable(false);
    output.setEditable(false);
    this.setTitle("聊天室for服务端");
    this.add(p);
    this.setSize(500, 300);
    this.setVisible(true);
}
public void buttonclose() {
    b1.setEnabled(true);
    b2.setEnabled(false);
    b3.setEnabled(false);
    input.setEditable(false);
}
public void buttonopen() {
    b1.setEnabled(false);
    b2.setEnabled(true);
    b3.setEnabled(true);
    input.setEditable(true);
}

public void disconnect() {
    started = false;
    bConnected = false;
    try {
        dos.writeUTF("$%$");
        dos.close();
        dis.close();
        s.close();
        System.out.println("Servicer dos.close");
        ss.close();
        System.out.println("Servicer cs.close");        
    } catch (IOException e) {
        e.printStackTrace();
    }
}
public void start() {
    try {
        ss = new ServerSocket(8888);
    } catch (IOException e) {
        e.printStackTrace();
    }

    try {   
        started = true;
        //while(started){
            s = ss.accept();
            output.append("新加入,已连接");
            buttonopen();
            bConnected = true;
            dos = new DataOutputStream(s.getOutputStream());
            dis = new DataInputStream(s.getInputStream());
            link();
        //}
    } catch (IOException e1) {
        e1.printStackTrace();
    }
}
public void send() {
    talking = input.getText().trim();
    try {
        if(talking == null) {
            dos.writeUTF("");
        } else {
            dos.writeUTF(talking);
        }
        dos.flush();
    } catch (IOException e1) {
        e1.printStackTrace();
    }
}

public void link() {
new Thread(){
        public void run() {
            String nicheng = null;
            try {
                nicheng = dis.readUTF();
            } catch (IOException e1) {
                output.append("\n\r用户名获取异常");
                e1.printStackTrace();
            }
            while (bConnected) {
                String talking = "";
                try {
                    talking = dis.readUTF();                            
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if("$%$".equalsIgnoreCase(talking)){
                    disconnect();
                }
                output.append("\n\r" + nicheng + " : " + talking);
            }

// try {
// dis.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
}
}.start();
}
public void actionPerformed(ActionEvent e) {
String S = e.getActionCommand();
String takeing = input.getText().toString();
if ("启动".equalsIgnoreCase(S)) {
start();
} else if ("退出".equalsIgnoreCase(S)) {
disconnect();
output.append("退出成功");
} else if ("发送".equalsIgnoreCase(S)) {
send();
output.append("\n\r" + "主机" + " : " + takeing);
input.setText("");
}
}

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

}

 服务器端代码修改一下 
private volatile boolean bConnected = false;//增加volatile


public void disconnect() {
    started = false;
    bConnected = false;
    try {
        dos.writeUTF("$%$");
        dos.close();
        dis.close();
        s.close();
        System.out.println("Servicer dos.close");
        ss.close();
        System.out.println("Servicer cs.close");
        buttonclose();//增加这句话,修改按钮状态
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Action.java(获得消息的Action)代码:/** * 进行聊天 */public String chat(int type, String text, String userId, String otherUserId, String matchId) { switch(type) { case 1: ......
答案就在这里:Java聊天室
----------------------Hi,地球人,我是问答机器人小S,上面的内容就是我狂拽酷炫叼炸天的答案,除了赞同,你还有别的选择吗?