有谁愿意帮我检查一下我的聊天室哪里错了??
上个月写了一个简单的聊天室,但功能不全,只能用客户端对客户端的形式进行对话,在服务器中不能发信息,但当进行客户之间进行公聊和私聊替换时,就偶尔出现了收不到信息的错误,我花了很长时间也找不到错误的所在.........如果大家愿意的话,请帮我看看究竟是怎么回事,谢谢了!//服务器端程序:
//11开头表示新加入了聊天用户;22开头表示公聊;33开头表示私聊
import *;
import javax.swing.*;
import java.awt.*;
import javax.swing.border.TitledBorder;
import java.awt.event.*;
import *;
import java.util.*;
public class Server1 extends JFrame
{
JTextArea JT2; // "聊天记录"那个文本域
JTextArea JT3; // "发送信息"那个文本域
JButton B1; // "发送"按钮
JButton B2; // "删除"按钮
final JCheckBox JC; //"发送给所有用户"复选框
TitledBorder TB1; //"参与者"边框
TitledBorder TB2; //"聊天记录"边框
TitledBorder TB3; //"发送信息"边框
Socket s; //客户端套接字
BufferedReader BR;
PrintWriter PW;
boolean bool=false;
boolean flag=true;
//String line=System.getProperty("line.separator"); //起到换行作用
HashMap map=new HashMap(); //用来储存socket和用户名
JList userList=new JList(); //用来显示参与者
DefaultListModel ListModel=new DefaultListModel();
Vector ve=new Vector(); //用来储存用户名
public Server1(String str)
{
super(str);
this.getContentPane().setLayout(null); //设置主窗口的布局管理器为空
//创建组件
JT2=new JTextArea(60,30);
JT2.setCaretPosition(JT2.getText().length());
JT3=new JTextArea(60,30);
B1=new JButton("发送");
B2=new JButton("删除");
JC=new JCheckBox("发送给所有用户");
TB1=BorderFactory.createTitledBorder("参与者");
TB2=BorderFactory.createTitledBorder("聊天记录");
TB3=BorderFactory.createTitledBorder("发送信息");
//创建面板
JPanel JP1=new JPanel();
JPanel JP2=new JPanel();
JPanel JP3=new JPanel();
JPanel JP4=new JPanel();
JPanel JP5=new JPanel();
//布置JP1面板
JP1.setLayout(new GridLayout(1,1));
userList.setModel(ListModel);
JScrollPane JS=new JScrollPane(userList); //创建滚动条
JS.setBorder(TB1); //添加边框
JP1.add(JS);
JP1.setBounds(7,10,150,425); //设置JP1面板的大小和坐标
this.getContentPane().add(JP1); //先用getContentPane()返回主窗口的面板,再在此面板中添加JP1
//布置JP2面板
JP2.add(JC);
JP2.setBounds(30,432,150,50);
this.getContentPane().add(JP2);
//布置JP3面板
JP3.setLayout(new GridLayout(1,1));
JT2.setEditable(false); //设置JT2文本域不可编辑
JScrollPane JSP2=new JScrollPane(JT2);
JSP2.setBorder(TB2);
JP3.add(JSP2);
JP3.setBounds(160,10,380,250);
this.getContentPane().add(JP3);
//布置JP4面板
JP4.setLayout(new GridLayout(1,1));
JScrollPane JSP3=new JScrollPane(JT3);
JSP3.setBorder(TB3);
JP4.add(JSP3);
JP4.setBounds(160,258,380,177);
this.getContentPane().add(JP4);
//布置JP5面板
JLabel j=new JLabel(" "); //此标签只起分隔B1和B2的作用
JP5.add(B1);
JP5.add(j);
JP5.add(B2);
JP5.setBounds(350,430,200,35);
this.getContentPane().add(JP5);
this.pack(); //用来整理组件的空隙
B1.addMouseListener(new action()); //为B1添加监听器,"acion"是一个类,在下面定义了
JC.addActionListener(new ActionListener() //为JC添加监听器
{
public void actionPerformed(ActionEvent e)
{
bool=JC.isSelected(); //用来标志此复选按钮是否被打勾
}
});
}
public void receive() //接收用户信息
{
try
{
ServerSocket ss=new ServerSocket(8000); //定义服务器套接字
while(flag)
{
s=ss.accept(); //接收用户的请求,并创建一个客户端套接字
work w=new work(s); //创建线程 w
w.start(); //启动线程
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
class action extends MouseAdapter //自定义监听器
{
public void mousePressed(MouseEvent e) //鼠标按下所以触发的事件
{
String str=JT3.getText(); //获取"发送信息"文本域的内容
PW.println(str); //向对应的输出流输出str
JT3.setText(""); //设置"发送信息"文本域为空
}
}
class work extends Thread //线程类
{
Socket s;
public work(Socket s)
{
this.s=s;
}
public void run()
{
try
{
InputStream in=s.getInputStream(); //获取相应的输入流
OutputStream out=s.getOutputStream(); //获取相应的输出流
BR=new BufferedReader(new InputStreamReader(in)); //创建输入流
PW=new PrintWriter(out,true); //创建输出流
String value;
String str=BR.readLine(); //读取从客户段传过来的数据
str=str.trim(); //读取输入流BR的内容
while(str.length()!=0)
{
Iterator it; //定义一个迭代器
int int_1=Integer.parseInt(str.substring(0,2)); //截取str的前两个字符
String str2=str.substring(2); //得到一个以索引2为起点的新字符串
Set keySet_; //用来保存用户名和相应的Socket
int num; //Vector数组的元素个数
switch(int_1) //验证str的前两个字符
{
case 11: //str以"11"开头的,表示新来的用户
ListModel.addElement(str2); //在列表中添加新的用户
ve.add(str2); //把用户名添加到Vector数组中
map.put(s,str2); //设置用户名的key和值
num=ve.size(); //返回Vector的元素个数
keySet_=map.keySet(); //返回所有key,即所有的Socket
it=keySet_.iterator(); //返回一个迭代器
while(it.hasNext()) //判断是否具有元素
{
Socket s1=(Socket)it.next(); //取得Socket
value=(String)map.get(s1); //返回对应Socket的值
PW=new PrintWriter(s1.getOutputStream(),true); //创建一个有对应客户端的输出流
PW.println("00aaaa"); //向对应的Socket客户端传输字符串"00aaaa"(作用:用来告诉客户端要清空用户列表)
for(int i=0;i<num;i++)
{
if(value!=ve.get(i)) //用来实现不向自己客户端列表发送自己的名字
{
PW.println("11"+(String)ve.get(i)); //发送以"11"开头的用户名到相应的客户端
}
}
}break;
case 22 : //以"22"开头,表示公聊
keySet_=map.keySet(); //返回所有key,即所有的Socket
it=keySet_.iterator(); //返回一个迭代器
while(it.hasNext()) //判断是否具有元素
{
Socket s1=(Socket)it.next(); //取得Socket
if(s1!=s) //用来实现:不向发信客户端的发送信息
{
PW=new PrintWriter(s1.getOutputStream(),true); //创建一个有对应客户端的输出流
PW.println("22"+map.get(s)+" 对大家说:"+str2); //向相应的客户端发送以"22"开头的信息
}
}break;
case 33 : //以"33"开头,表示私聊
int index=str2.indexOf("++"); //用来作为名字标记,因为用户名字后面直接跟上"++"
String userName=str2.substring(0,index); //获取str2中包含的用户名
String str3=str2.substring(index+2); //获取纯的聊天信息(次信息不包括任何标记,只是纯谈话信息)
keySet_=map.keySet();
it=keySet_.iterator();
while(it.hasNext())
{
Socket s1=(Socket)it.next();
value=(String)map.get(s1);
if(value.equals(userName)) //当找到相应的要发送的用户时则为真
{
PW=new PrintWriter(s1.getOutputStream(),true);
PW.println("33"+map.get(s)+" 对你说:"+str3);
}
}break;
}
str=BR.readLine();
str=str.trim(); //清楚字符串前后的空白
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
public static void main(String[] args)
{
Server1 S=new Server1("聊天室服务器");
S.setSize(550,500); //设置主窗口的大小
S.setLocation(150,150); //设置主窗口的位置
S.setResizable(false); //设置主窗口不可改变大小
S.setVisible(true); //设置主窗口可见
S.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //为主窗口添加关闭的监听器
S.receive(); //调用接收信息的方法
}
}
//客户端端程序:
//11开头表示新加入了聊天用户;22开头表示公聊;33开头表示私聊
import javax.swing.*;
import *;
import java.awt.*;
import javax.swing.border.TitledBorder;
import *;
import java.awt.event.*;
public class Client1 extends JFrame
{
JTextArea JT2; // "聊天记录"那个文本域
JTextArea JT3; // "发送信息"那个文本域
JButton B1;
JButton B2;
JCheckBox JC; //"发送给所有用户"复选框
TitledBorder TB1; //"参与者"边框
TitledBorder TB2; //"聊天记录"边框
TitledBorder TB3; //"发送信息"边框
BufferedReader BR;
PrintWriter PW;
boolean bool=false;
final JList userList=new JList();
DefaultListModel ListModel=new DefaultListModel();
//String line=System.getProperty("line.separator"); //起到换行作用
String userName;
public Client1(String str)
{
super(str);
this.getContentPane().setLayout(null); //设置主窗口的布局管理器为空
//创建组件
JT2=new JTextArea(60,30);
JT3=new JTextArea(null,60,30);
B1=new JButton("发送");
B2=new JButton("离线");
JC=new JCheckBox("发送给所有用户");
TB1=BorderFactory.createTitledBorder("参与者");
TB2=BorderFactory.createTitledBorder("聊天记录");
TB3=BorderFactory.createTitledBorder("发送信息");
//创建面板
JPanel JP1=new JPanel();
JPanel JP2=new JPanel();
JPanel JP3=new JPanel();
JPanel JP4=new JPanel();
JPanel JP5=new JPanel();
//布置JP1面板
JP1.setLayout(new GridLayout(1,1));
userList.setModel(ListModel);
JScrollPane JSP1=new JScrollPane(userList); //创建滚动条
JSP1.setBorder(TB1); //添加边框
JP1.add(JSP1);
JP1.setBounds(7,10,150,425); //设置JP1面板的大小和坐标
this.getContentPane().add(JP1); //先用getContentPane()返回主窗口的面板,再在此面板中添加JP1
//布置JP2面板
JP2.add(JC);
JP2.setBounds(30,432,150,50);
this.getContentPane().add(JP2);
//布置JP3面板
JP3.setLayout(new GridLayout(1,1));
JT2.setEditable(false); //设置JT2文本域不可编辑
JScrollPane JSP2=new JScrollPane(JT2);
JSP2.setBorder(TB2);
JP3.add(JSP2);
JP3.setBounds(160,10,380,250);
this.getContentPane().add(JP3);
//布置JP4面板
JP4.setLayout(new GridLayout(1,1));
JScrollPane JSP3=new JScrollPane(JT3);
JSP3.setBorder(TB3);
JP4.add(JSP3);
JP4.setBounds(160,258,380,177);
this.getContentPane().add(JP4);
//布置JP5面板
JLabel j=new JLabel(" "); //此标签只起分隔B1和B2的作用
JP5.add(B1);
JP5.add(j);
JP5.add(B2);
JP5.setBounds(350,430,200,35);
this.getContentPane().add(JP5);
this.pack(); //用来整理组件的空隙
B1.addMouseListener(new action()); //为"发送"按钮添加监听器
JC.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
bool=JC.isSelected(); //判断复选框是否被打勾
}
});
userList.addMouseListener(new user());
}
class user extends MouseAdapter
{
public void mousePressed(MouseEvent e)
{
userName=(String)userList.getSelectedValue(); //返回当前你选择的用户名
}
}
public void receive() //接收信息的方法
{
try
{
Socket s=new Socket(InetAddress.getByName(null),8000); //创建指定IP地址的套接字(Socket)
InputStream in=s.getInputStream(); //获得相应的输入流
OutputStream out=s.getOutputStream(); //获得相应的输出流
BR=new BufferedReader(new InputStreamReader(in));
PW=new PrintWriter(out,true);
PW.println("11Javapet"); //向服务器发送此客户端的用户名
work w=new work(); //创建一个线程
w.start(); //启动线程
}
catch(Exception e)
{
e.printStackTrace();
}
}
class action extends MouseAdapter
{
public void mousePressed(MouseEvent e)
{
String str=JT3.getText(); //获取
if(str.length()!=0) //判断输入的信息是否为空
{
if(userName==null) //判断是否选中用户名
{
if(bool) //判断复选框是否被打勾
{
JT2.append("你对所有人说:"+str); //把你所输入的信息打印到"聊天记录"中
PW.println("22"+str); //向服务器发送以开头"22"聊天信息,"22"表示公聊
}
userName=null; //不再选中用户名
}
else //表示信息将要发送到哪个用户名
{
if(bool) //判断复选框是否被打勾
{
JT2.append("你对所有人说:"+str); //把你所输入的信息打印到"聊天记录"中
PW.println("22"+str); //向服务器发送以开头"22"聊天信息,"22"表示公聊
}
else
{
JT2.append("你对 "+userName+" 说:"+str); //把你所输入的信息打印到"聊天记录"中
PW.println("33"+userName+"++"+str); //向服务器发送以开头"33"聊天信息,"33"表示私聊
}
}
}
}
}
class work extends Thread //此线程主要用来无量循环地接收服务器转发过来的信息
{
public void run()
{
while(true)
{
try
{
String str=BR.readLine();
String str2=str.substring(0,2);
int int_=Integer.parseInt(str2);
String str3=str.substring(2); //获取聊天信息 if(str.startsWith("00")) //判断str是否含有"00",有的话,就把用户列表清空,再等待新的列表名单
{
ListModel.removeAllElements();
}
else if(int_==11) //判断是否以"11"开头
{
ListModel.addElement(str3); //把用户名添加到列表中
}
else if(int_==22||int_==33) //判断是否是以"22"或"33"开头
{
JT2.append(str3); //把内容添加到"聊天记录"里
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
public static void main(String[] args)
{
Client1 C=new Client1("Javapet聊天室");
C.setSize(550,500); //设置主窗口的大小
C.setLocation(150,150); //设置主窗口的位置
C.setResizable(false); //设置主窗口不可改变大小
C.setVisible(true); //设置主窗口可见
C.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //为主窗口添加关闭的监听器
C.receive(); //调用接收信息的方法
}
}