这是客户端
import java.util.List; 
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
//import java.awt.List;
import java.util.*; 
import java.util.ArrayList;
import javax.swing.Box;public class Chat extends Frame
{
DataInputStream dis = null;

DataOutputStream dos = null; Socket socket = null;
TextArea tf = new TextArea( 2 ,70);
TextArea ta = new TextArea(40 ,70 );
TextArea arr = new TextArea();
Button btn = new Button("发送");
java.awt.List lasd;
int temp = 0;
//List<String> name = new ArrayList<String>();
//static List<String> name = new ArrayList<String>();

static String[] name = new String[10];
TextField t = null;
boolean join = false;//是否从服务器接受到信息 public static void main(String[] args) 
{
//new Chat().showFrame();
new Chat().land();
}

public void land() //登陆界面
{
Button bt = new Button("登陆");
t = new TextField(10);
Label lb = new Label("请输入用户名");
CheckboxGroup cbg = new CheckboxGroup();
Panel lbPanel = new Panel();
Panel btPanel = new Panel();
Panel checkPanel = new Panel();
Panel tPanel = new Panel();
Checkbox boy = new Checkbox("男", cbg , true);
Checkbox girl = new Checkbox("女" , cbg , false);

bt.addActionListener(new button());
setLayout(new GridLayout(4 , 1)); lbPanel.add(lb);
btPanel.add(bt);
tPanel.add(t);
checkPanel.add(boy);
checkPanel.add(girl);
add(lbPanel );
add(tPanel );
add(checkPanel);
add(btPanel);
setBounds(30 , 30 , 150 ,140);
setResizable(false) ;
//pack();
setVisible(true);

this.addWindowListener(new WindowAdapter()//窗口关闭
{
@Override
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
}  class button implements ActionListener//登陆事件
{
public void actionPerformed(ActionEvent e)
{
Frame f = new Frame("提示");
Button b1 = new Button("请输入用户名");
Dialog dl = new Dialog(f ,"提示" , true);
dl.setBounds(300 , 300 , 70 , 50);
dl.add(b1);


if (t.getText().equals(""))
{
dl.setVisible(true);
}

else
{
name[temp] = t.getText();
setVisible(false);
System.out.println(name[temp]);
new Chat().showFrame();


}
for (int i = 0;i < name.length ; i++ )
{System.out.println(name[i]);
}

}
} public void showFrame()
{

this.addWindowListener(new WindowAdapter()//窗口关闭
{
@Override
public void windowClosing(WindowEvent e)
{
dosClose();
System.exit(0);
}
});
Label lb = new Label("聊天窗口");
Label lb1 = new Label("信息内容");
Panel pan = new Panel();
Panel pan1 = new Panel();
Panel pan2 = new Panel();
Panel pan3 = new Panel();
Panel pan4 = new Panel();

lasd = new java.awt.List(41 , true);//列表
setBounds(30 , 30 , 780 ,730);//窗口大小

setResizable(false);//是否可以改变大小
setLocation(280 , 280);//窗口出来位置
Box top = Box.createHorizontalBox();//存放列表
lasd.add("用户列表");
//lasd.add(name[temp]); lasd.add(name[temp]);
pan.add(ta);
pan1.add(tf);
pan2.add(btn);
pan3.add(lb);
pan4.add(lb1);
//pan2.add(cho);
setLayout(new FlowLayout(FlowLayout.LEFT , 5 , 1));
//setLayout(new GridLayout(3 ,2));
top.add(lasd);

add(pan3);
add(pan);
add(top);
//add(arr , BorderLayout.EAST);
add(pan4);
add(pan1);
add(pan2);
//pack();
btn.addActionListener(new textField());
setVisible(true);
isServer();
new Thread(new InChat()).start();//启动线程
}
public void isServer()//客户
{
try
{
socket = new Socket("127.0.0.1" , 33333);
dos = new DataOutputStream(socket.getOutputStream());

dis = new DataInputStream(socket.getInputStream());

join = true;
}
catch (IOException ex)
{
ex.printStackTrace();
}

}
public void dosClose()//关闭
{
try
{
dos.close();
dis.close();
socket.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
private class textField implements ActionListener
{

public void actionPerformed(ActionEvent e)
{
String str = tf.getText();
//ta.setText(str);
tf.setText("");
try
{
dos.writeUTF(name[temp] + "说:" + str);

dos.flush();
//dos.close();

}
catch (IOException ex)
{
ex.printStackTrace();
}


}
}
class InChat implements Runnable
{
public void run()
{
try
{ while (join)
{
String str = dis.readUTF();
ta.setText(ta.getText() + str + "\n");
}
}
catch (Exception ex)
{
System.out.println("退出聊天室");
}
}
}
}

解决方案 »

  1.   

    这是服务器
    import java.net.*;
    import java.io.*;
    import java.util.*;public class CharServer
    {
    boolean flag = false;//服务器是否连上
    ServerSocket ss = null;
    List<MoreThread> morethread = new ArrayList<MoreThread>(); public static void main(String[] args) 
    {
    new CharServer().start();

    }
    public void start()
    {
    try
    {
    ss = new ServerSocket(33333);
    flag = true;
    }
    catch (IOException ex)
    {
    System.out.println("端口使用中");
    }
    try
    {

    while (flag)
    {

    Socket s = ss.accept();
    MoreThread mt = new MoreThread(s);
    System.out.println("欢迎你进入聊天室"); //测试
    new Thread(mt).start();//启动多线程
    morethread.add(mt);
    }
    }
    catch (IOException ex)
    {
    ex.printStackTrace();
    }
    }

    class MoreThread implements Runnable //实现多线程
    {
    private Socket s = null;
    private DataInputStream dis = null;
    private DataInputStream dss = null;
    private boolean boo = false;//是否接受到客户信息
    private DataOutputStream dos = null;
    public MoreThread(Socket s)
    {

    this.s = s;
    try
    {
    dis = new DataInputStream(s.getInputStream());

    dos = new DataOutputStream(s.getOutputStream());

    boo = true;

    }
    catch (Exception ex)
    {
    ex.printStackTrace();
    }

    } public void send(String line)
    {
    try
    {
    dos.writeUTF(line);
    }
    catch (Exception ex)
    {
    ex.printStackTrace();
    }
    } public void run()
    {
    MoreThread mt = null;

    try
    {
    while (boo)
    {
    String line = dis.readUTF();

    //System.out.println(line);
    for (int i = 0 ; i < morethread.size() ; i ++ )//遍历每个客户发送信息
    {
    mt = morethread.get(i);
    mt.send(line);

    }


    }
    }
    catch (IOException ex)
    {
    try
    {
    dis.close();
    dos.close();
    s.close();
    }
    catch (Exception e)
    {
    e.printStackTrace();
    }
    if (mt != null)
    {
    morethread.remove(mt);
    }
    }


    }
    }
    }
      

  2.   

    用户联上来的时候就可以保存他的名字在一个list里面,显示的时候显示这个list里的名字,断开连接的时候在把名字从list里去掉,关闭连接这种业务最好都放在finally里 
      

  3.   

    我觉得在客户端和服务器间的通信应该定义成一种协议。比如,每次通信的消息包括两部分消息头和消息体。消息头就是这个消息的类型(可以标识用户列表、发送类型或者就是客户端发送的信息),消息体就是内容。有了这种协议你完全可以实现单发、组发和群发等功能,只要将这些信息存入消息头中即可。如果采用协议的方式的话,我觉得用对象流会更方便,可以直接将消息的类型声明为类,得到消息后就可以用instanceof非常方便。
      

  4.   

    你把用户存储到一个list里面 新上线一个用户就用add方法添加到list里面
    最后循环list集合 展示所有用户
    如果你连了数据库的话 更加好做 你可以在数据库中的用户表设置一个用户状态字段
    比如说:0离线 1在线 每一个用户登录成功 就改变状态 最后循环所有状态为1的用户就行了 
    当然 第二种 性能不好 还是第一种好一点 
      

  5.   

    可以定义Protocol类来实现协议,包括属性String header和Object body。并改用对象流。
    客户端可以发送new Protocol("userName","用户名")和new Protocol("Message","内容")。
    服务器端可发送new Protocol("userList","用户名")和new Protocol("Message","内容")。客户端:
          一登录就向服务器发送new Protocol("userName","用户名")
          while(join){
             //读取客户端发来的协议
             Protocal p=(Protocal)dis.readObject();
             if(p的消息头是message)
          显示消息
     else if(p的消息头是userList){
          根据p的消息体,更改List
             }
         }服务器端:
           
            while (boo) 
           { 
       //读取客户端发来的协议
       Protocal p=(Protocal)dis.readObject();
       if(p的消息头是message){
                  遍历所有客户端,向它们发送new Protocol("Message","内容")。
               }
       else if(p.getHeader().equals("userName")){
                  将p的消息体中的内容加入用户列表list中
                  遍历所有客户端,向它们发送new Protocol("userList","用户名")
               }
           }

    这是我的想法,核心部分的,看对楼主有没有帮助