Javapet 发表于 2008-4-15 16:33

有谁愿意帮我检查一下我的聊天室哪里错了??

上个月写了一个简单的聊天室,但功能不全,只能用客户端对客户端的形式进行对话,在服务器中不能发信息,但当进行客户之间谈话时,就偶尔出现了收不到信息的错误,我花了很多时间也找不到错误的所在.........如果大家愿意的话,请帮我看看究竟是怎么回事,谢谢了!
[attach]33898[/attach]

//服务器端程序:
//11开头表示新加入了聊天用户;22开头表示公聊;33开头表示私聊

import java.io.*;
import javax.swing.*;
import java.awt.*;
import javax.swing.border.TitledBorder;
import java.awt.event.*;
import java.net.*;
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 java.io.*;
import java.awt.*;
import javax.swing.border.TitledBorder;
import java.net.*;
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();                   //调用接收信息的方法
                }
}

[[it] 本帖最后由 Javapet 于 2008-4-15 20:00 编辑 [/it]]

luyihuaa5201 发表于 2008-4-15 17:41

J2SE论坛中有个一样的!  你照着看哈,我也不是蛮懂!~

web023123 发表于 2008-4-16 11:00

- -!这么长。你干嘛不把出错的消息发出来看看

web023123 发表于 2008-4-16 11:00

这么长。你干嘛不把运行出错的消息发出来

Javapet 发表于 2008-4-16 12:32

这个我在“命令提示”中运行时没有错误的,只是在用的时候有时会收不到信息

Starlove 发表于 2008-4-18 15:25

似乎是j2se的问题
发错地方了

恋轩念伊人 发表于 2008-4-20 13:34

发这里也没有很大关系吧

netstriker 发表于 2008-4-20 21:13

已经修改好了,其实问题并不大,只是没有考滤有一种情况而已,同时,如果是服务器跟客户这样来发送信息的话,是有缺憾的,比如,现在这样去跟客户端去发送信息,只有最后一个连接上服务器端的客户端可以跟服务器交流信息.因为这一个PrintWriter是最后连接上服务器的pw对象,所以,这一个方面的话,要再改进.

Javapet 发表于 2008-4-24 15:12

哦,好,我再看看你修改后的代码,真的很感谢你的帮忙!

Javapet 发表于 2008-4-24 15:55

你好,很感谢你帮我修改了代码,我想知道我哪种情况没有考虑到?还有,程序在运行时如果各个客户端公聊和私聊不断地替换操作,发送到一定程度时,仍然会出现收不到信息的情况,请问是不是我的程序架构有问题,有人说我的程序是过程式的程序,要求我用oo模式重新设计,不过现在不管是过程式还是oo模式,我只想知道我的程序具体哪里错了,请指教,谢谢了!

页: [1]

编程论坛