java socket聊天室 swing做界面 Tcp为通讯协议 支持私聊 群聊 发文件

来源:互联网 发布:mac版flash 官方下载 编辑:程序博客网 时间:2024/05/14 05:39

                                                       java聊天室


            首先我们来看看程序界面,丑到爆!!!,勉强能用就行啦微笑

           第一个:登录界面

                    


              第二个:用户界面

                        


                   第三个:服务器界面

            


          好了上面三个界面是程序的主界面,下面我们先讲讲如何使用源代码

             使用条件:     一。 数据库,我这里用mysql数据库,如果使用其他数据库比如oracle

                                      需要去cn.scau.util包的DBproperties配置文件中重新配置数据库参数

                                                    我们来看看原来的配置

                               比如username   password   url使用jdbc的朋友应该更懂,还有自己导入对应数据库的驱动包


                                 二。数据库中所用到的表

                                                                  首先看看表结构

                                                                  说明一下各个字段的类型:

                                                               字段                            类型

                                                        register_time       :       TIMESTAMP

                                                                                   username          :        VARCHAR

                                                          password            :        VARCHAR

                                                          nickname             :         VARCHAR

                                                           user_id              :            INT

                                           所以要建立chatuser表先,再在配置文件DBproperties中配置数据库


                      三:我是用netbeans 编写的,如果用netbeans导入项目的话,再满足上面两个条件就可以运行啦


   好了讲完使用,我们来说说程序的整体思路

      首先看看客户端和服务端的流程图



    什么意思呢??我来解释一下

   首先,图中有三个类,一个方法。三个类分别是:ServerThread,ClientThreadMessageThread

                  一个方法: conServer

   其中:ServerThread,ClientThread属于服务器的类,而MessageThread,conServer属于客户端

 

   最后:依照流程图,首先客户端的conServer,发起向服务端的连接,服务端的ServerThread是提前开

      启的,ServerThread线程接受客户端的连接,新建一个ClientThread线程为这个新连接的客户端服务

      这里的服务是接受这个客户端的信息,和向这个客户端发送信息,同时呢,在遥远的青青草原

      上的客户端也会开启一个线程,它就是MessageThread,专门用来接收来自服务端对应的           ClientThread线程发来的消息。


      为什么这样呢,因为这样服务端每次接收到新的客户端的连接,就会为它分配一个ClientThread线程

      我们在服务端维护这个ClientThread线程列表,就可以区分每个客户端了,由于每个客户端在服务器

      都有一个对应的ClientThread线程,所以客户端发送的信息也不会乱。


最后我们来看看流程图中的代码,也是这个聊天室的核心

 //服务器线程,用来接收用户登录    class ServerThread extends Thread {        private boolean ifopen;        private ServerSocket serverSocket;        public ServerThread() {            this.ifopen = true;        }        @Override        public void run() {            try {                serverSocket = new ServerSocket(port);                JOptionPane.showMessageDialog(su.getJframe(), "服务器成功启动");                while (ifopen) {                    Socket clnSocket = serverSocket.accept();//阻塞接收客户端的连接                    if (userList.size() == max) {                        su.getShowMessage().append("有客户端尝试连接服务端,但在线人数已达上限" + ServerUtil.getTime() + "\r\n");                        clnSocket.close();                        continue;                    }                    //每个客户端都有对应的线程处理                    ClientThread client = new ClientThread(clnSocket);                    su.getListModel().addElement(client.user.getName());//用户列表更新                    userList.put(client.getUser().getName(), client);                    client.start();                }            } catch (BindException be) {                JOptionPane.showMessageDialog(su.getJframe(), "端口已经被占用,请重新启动!", "error", JOptionPane.ERROR_MESSAGE);                return;            } catch (Exception ex) {                ex.printStackTrace();            }        }        public ServerSocket getServerSocket() {            return serverSocket;        }        public void setIfopen(boolean ifopen) {            this.ifopen = ifopen;        }    } /*    每个连接到服务器的Client,都有一个线程来单独处理,接受消息     */    class ClientThread extends Thread {        private ObjectOutputStream oos;        private ObjectInputStream ois;        private Socket socket;        private User user;        private boolean ifopen;        public void PrivateSend(String message) {        }//        每个客户端对应一个客户端线程处理        public ClientThread(Socket socket) {            this.ifopen = true;            this.socket = socket;            try {                ois = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));                oos = new ObjectOutputStream(socket.getOutputStream());                Object obj = ois.readObject();//读取用户信息包------------------------------------读取包                DataBag db = (DataBag) obj;//取得数据包,第一个数据包存储了用户的信息                this.user = db.getUser();//首先得到登录用户的信息                //通知其他客户端,新用户上线                BagTarget bt = new BagTarget();                bt.setOption(GROUP_CHAT);                bt.setGroupOption(USER_ADD);                db.setBt(bt);//----------------------3目的地数据                GroupSend(db);//--------------------------------------------向其他在线用户群发有新的用户登录包                //向刚登录的用户发送当前在线的用户列表                if (userList.size() > 0) {                    DataBag dblist = new DataBag();                    HashMap onlineUser = new HashMap();                    Iterator iter = userList.entrySet().iterator();                    while (iter.hasNext()) {                        Map.Entry entry = (Map.Entry) iter.next();                        String key = (String) entry.getKey();                        ClientThread val = (ClientThread) entry.getValue();                        onlineUser.put(key, val.getUser());                    }                    dblist.setUserlist(onlineUser);//-----------------------4在线的用户                    BagTarget btList = new BagTarget();                    btList.setOption(GROUP_CHAT);                    btList.setGroupOption(USER_LIST);                    dblist.setBt(btList);//曾经的bug出错点-------------------------------------bug     bug           bug------------------------------>                    oos.writeObject(dblist);                    oos.flush();                }            } catch (Exception ex) {                System.out.println(ex.getMessage());                ex.printStackTrace();            }        }//         重写run方法,用来循环接受消息        @Override        public void run() {            while (this.ifopen) {                try {                    Object obj = ois.readObject();                    DataBag db = (DataBag) obj;                    int option = db.getBt().getOption();//知道数据包要干嘛,私聊还是群聊- 0是群聊,1是私聊                    switch (option) {                        case GROUP_CHAT:                            GroupChat(db);                            break;                        case PRIVATE_CHAT:                            PrivateChat(db);                            break;                        default:                    }                } catch (IOException ex) {                    ex.printStackTrace();                } catch (ClassNotFoundException ex) {                    ex.printStackTrace();                }            }        }        synchronized public ObjectOutputStream getOos() {            return oos;        }        public User getUser() {            return user;        }        public void setIfopen(boolean ifopen) {            this.ifopen = ifopen;        }    }    // class MessageThread extends Thread {        private boolean ifopen;        public MessageThread() {            this.ifopen = true;        }        @Override        public void run() {            try {                oos = new ObjectOutputStream(socket.getOutputStream());                ois = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));                //先发送自身的信息给服务器                DataBag db = new DataBag();                db.setUser(user);                oos.writeObject(db);                oos.flush();                while (ifopen) {                    Object obj = ois.readObject();                    db = (DataBag) obj;                    int option = db.getBt().getOption();//判断是私聊还是群聊                    switch (option) {                        case GROUP_CHAT:                            GroupChat(db);                            break;                        case PRIVATE_CHAT:                            PrivateRecv(db);                            break;                        default:                    }                }            } catch (Exception ex) {                System.out.println(ex.getMessage());                ex.printStackTrace();            }        }        public void setIfopen(boolean ifopen) {            this.ifopen = ifopen;        }    } public void conServer(User user) {        String name = null;        String ip = null;        int port = 0;        try {            name = user.getName();            ip = user.getTargetIp();            port = user.getPort();            conCheck(name, ip, port);//throw 检查中的异常            this.socket = new Socket(ip, port);//生成客户端socket            //String userList = bfread.readLine();            //接受消息的线程启动            mt = new MessageThread();            mt.start();            /*            if (socket.isClosed() == false) {                JOptionPane.showMessageDialog(cu.getJframe(), "连接成功");            }*/            this.iflogin = true;        } catch (IOException ex) {            this.iflogin = false;            cu.getShowMessage().append("连接服务ip:" + ip + "端口:" + port + "的服务器失败!" + ClientUtil.getTime() + "\r\n");            ex.printStackTrace();        } catch (Exception ex) {            this.iflogin = false;            JOptionPane.showMessageDialog(cu.getJframe(), ex.getMessage());        }    } //    //服务器线程,用来接收用户登录    class ServerThread extends Thread {        private boolean ifopen;        private ServerSocket serverSocket;        public ServerThread() {            this.ifopen = true;        }        @Override        public void run() {            try {                serverSocket = new ServerSocket(port);                JOptionPane.showMessageDialog(su.getJframe(), "服务器成功启动");                while (ifopen) {                    Socket clnSocket = serverSocket.accept();//阻塞接收客户端的连接                    if (userList.size() == max) {                        su.getShowMessage().append("有客户端尝试连接服务端,但在线人数已达上限" + ServerUtil.getTime() + "\r\n");                        clnSocket.close();                        continue;                    }                    //每个客户端都有对应的线程处理                    ClientThread client = new ClientThread(clnSocket);                    su.getListModel().addElement(client.user.getName());//用户列表更新                    userList.put(client.getUser().getName(), client);                    client.start();                }            } catch (BindException be) {                JOptionPane.showMessageDialog(su.getJframe(), "端口已经被占用,请重新启动!", "error", JOptionPane.ERROR_MESSAGE);                return;            } catch (Exception ex) {                ex.printStackTrace();            }        }        public ServerSocket getServerSocket() {            return serverSocket;        }        public void setIfopen(boolean ifopen) {            this.ifopen = ifopen;        }    }

各位看官有问题的话请评论留言,我有空就过来回答


源代码在我的资源中下载,不用积分