zoukankan      html  css  js  c++  java
  • JAVA入门到精通-第92讲-山寨QQ项目6-多对多的聊天

    QQ聊天项目演示-多对多的聊天
    流同时并发的异常;

    服务器中转
    2/3号只有一个连接;

    接收信息:while循环不停地读取;

    当1号点开两个窗口时,2/3会共同去争取这个socket;
    会出现流同时并发异常;

    Socket处理成static不太合理;

    启动一个窗口就会占据Socket不放;

    -------------
    -实现真正的多人聊天,互相不出现错误
    -每一个登录的账号独享一份socket
    -去掉static
    当一个链接达成的时候,
    启动线程,
    和服务器保持通讯的状态;
    做一个类来管理客户端这边的线程;

    -新的账号登录,开一个线程ClientConServerThread

    -管理线程的类,放入到一个HashMap里面:ManageClientConServerThread;

    HashMap<k,v>
    k:用户账号,某个账号独享的线程
    v:ClientConServerThread


    -----------------
    -当账号登录成功,创建线程,把线程放入HashMap




    --------------------
    Qq聊天界面没有必要成为一个线程;本身是不合理的;

    通过 管理线程的类,取得了线程,通过线程取得socket,
    通过socket,取得了输出流:getOutputStream;

    ----------------------
    给每一个登录账号分配线程;
    把通讯的任务交给线程类;
    ---------------------

    -多对多聊天
    经测试,后台发送消息正常;

    ---------------
    -显示后台的消息到各自的聊天界面

    QqChat.java]

    110
    110
     
    1
    /**
    2
     * 这是与好友聊天的界面
    3
     * 因为客户端,要处于读取的状态,因此我们把它做成一个线程
    4
     */
    5
    package com.qq.client.view;
    6
     
    7
    import java.awt.event.ActionEvent;
    8
    import java.awt.event.ActionListener;
    9
    import java.io.IOException;
    10
    import java.io.ObjectInputStream;
    11
    import java.io.ObjectOutputStream;
    12
    import java.util.Date;
    13
    import javax.swing.ImageIcon;
    14
    import javax.swing.JButton;
    15
    import javax.swing.JFrame;
    16
    import javax.swing.JPanel;
    17
    import javax.swing.JScrollPane;
    18
    import javax.swing.JTextArea;
    19
    import javax.swing.JTextField;
    20
    import com.qq.client.model.QqClientConServer;
    21
    import com.qq.client.tools.ManageClientConServerThread;
    22
    import com.qq.common.Message;
    23
    import com.qq.common.MessageType;
    24
     
    25
    public class QqChat extends JFrame implements ActionListener {
    26
        JTextArea jta;
    27
        JTextField jtf;
    28
        JButton jb;
    29
        JPanel jp;
    30
        JScrollPane jsp;
    31
        String ownerId;
    32
        String friendId;
    33
     
    34
        // public static void main(String[] args) {
    35
        // new QqChat("小四");
    36
        // }
    37
     
    38
        // 构造函数
    39
        public QqChat(String friendId, String ownerId) {
    40
            this.ownerId = ownerId;
    41
            this.friendId = friendId;
    42
     
    43
            jta = new JTextArea();
    44
            jtf = new JTextField(15);
    45
            jb = new JButton("发送");
    46
            jb.addActionListener(this);
    47
            jp = new JPanel();
    48
            jp.add(jtf);
    49
            jp.add(jb);
    50
            jsp = new JScrollPane(jta);
    51
     
    52
            this.add(jsp, "Center");
    53
            this.add(jp, "South");
    54
     
    55
            this.setTitle(ownerId + " 正在与 " + friendId + " 聊天");
    56
            this.setSize(350, 300);
    57
            this.setIconImage((new ImageIcon("image/qie.jpg")).getImage());
    58
            this.setLocationRelativeTo(null);
    59
            this.setVisible(true);
    60
        }
    61
     
    62
        // 写一个方法,让它显示消息
    63
        public void showMessage(Message m){
    64
            String info=m.getSender()+" 对 "+m.getGetder()+" 说:"+m.getCon()+"
    ";
    65
            jta.append(info);
    66
        }
    67
     
    68
        @Override
    69
        public void actionPerformed(ActionEvent e) {
    70
            if (e.getSource() == jb) {
    71
                // 如果用户点击了发送按钮
    72
                Message m = new Message();
    73
                m.setMesType(MessageType.message_comm_mes);
    74
                m.setSender(this.ownerId);
    75
                m.setGetder(this.friendId);
    76
                m.setCon(this.jtf.getText());
    77
                m.setSendTime(new Date().toString());
    78
                jta.append(ownerId + " 对 " + friendId + " 说:" + jtf.getText()
    79
                        + "
    ");
    80
                jtf.setText("");
    81
                // 发送给服务器
    82
                try {
    83
                    ObjectOutputStream oos = new ObjectOutputStream(
    84
                            ManageClientConServerThread
    85
                                    .getClientConServerThread(ownerId).getS()
    86
                                    .getOutputStream());
    87
                    oos.writeObject(m);
    88
                } catch (Exception e1) {
    89
                    e1.printStackTrace();
    90
                }
    91
            }
    92
        }
    93
     
    94
        // @Override
    95
        // public void run() {
    96
        // while(true){
    97
        // //读取[如果读不到就等待]
    98
        // try {
    99
        // ObjectInputStream ois=new
    100
        // ObjectInputStream(QqClientConServer.s.getInputStream());
    101
        // Message m=(Message)ois.readObject();
    102
        // //显示出来
    103
        // String info=m.getSender()+" 对 "+m.getGetder()+" 说:"+m.getCon()+"
    ";
    104
        // jta.append(info);
    105
        // } catch (Exception e) {
    106
        // e.printStackTrace();
    107
        // }
    108
        // }
    109
        // }
    110
    }

    *******************************************************************************

    com.qq.client.model

    [QqClienConServer.java]

    54
    54
     
    1
    /**
    2
     * 这是客户端连接服务器的后台
    3
     * 功能:客户端与服务器进行数据交互
    4
     */
    5
    package com.qq.client.model;
    6
     
    7
    import java.io.ObjectInputStream;
    8
    import java.io.ObjectOutputStream;
    9
    import java.net.Socket;
    10
    import com.qq.client.tools.ClientConServerThread;
    11
    import com.qq.client.tools.ManageClientConServerThread;
    12
    import com.qq.common.Message;
    13
    import com.qq.common.User;
    14
     
    15
    public class QqClientConServer {
    16
        public Socket s;
    17
       
    18
        //发送第一次请求
    19
        public boolean sendLoginInfoToServer(Object o){
    20
            boolean b=false;
    21
           
    22
            try {
    23
                s=new Socket("127.0.0.1",9999);
    24
                ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream());
    25
                oos.writeObject(o);
    26
               
    27
                ObjectInputStream ois=new ObjectInputStream(s.getInputStream());
    28
                Message ms=(Message)ois.readObject();
    29
                //这里就是验证用户登录的地方
    30
                if(ms.getMesType().equals("1")){
    31
                    b=true;
    32
                    //就创建一个该qq号和服务器端保持通讯连接的线程
    33
                    ClientConServerThread ccst=new ClientConServerThread(s);
    34
                    //启动该通讯线程
    35
                    ccst.start();
    36
                   
    37
                    ManageClientConServerThread.addClientConServerThread(((User)o).getUserId(), ccst);
    38
                }
    39
            } catch (Exception e) {
    40
                e.printStackTrace();
    41
            } finally{
    42
            }
    43
            return b;
    44
        }
    45
       
    46
        //向服务器发送一个对象
    47
        public void SendInfoToServer(Object o){
    48
            try {
    49
                Socket s=new Socket("127.0.0.1",9999);
    50
            } catch (Exception e) {
    51
                e.printStackTrace();
    52
            } finally{
    53
            }
    54
        }

    }

    *******************************************************************************

    [QqClientUser.java]

    15
    15
     
    1
    /**
    2
     * 用户操作逻辑类
    3
     * QqClientUser会调用QqClientConServer的
    4
     * 方法sendLoginInfoToServer向服务器发送
    5
     */
    6
    package com.qq.client.model;
    7
     
    8
    import com.qq.common.User;
    9
     
    10
    public class QqClientUser {
    11
        //验证用户是否合法
    12
        public boolean checkUser(User u){
    13
            return new QqClientConServer().sendLoginInfoToServer(u);
    14
        }
    15
    }

    *******************************************************************************

    com.qq.client.tools

    [ClientConServerThread.java]

    58
    58
     
    1
    /**
    2
     * 这是客户端和服务器端保持通讯的线程
    3
     */
    4
    package com.qq.client.tools;
    5
     
    6
    import java.io.ObjectInputStream;
    7
    import java.net.Socket;
    8
    import com.qq.client.view.QqChat;
    9
    import com.qq.client.view.QqFriendList;
    10
    import com.qq.common.Message;
    11
    import com.qq.common.MessageType;
    12
     
    13
    public class ClientConServerThread extends Thread{
    14
        private Socket s;
    15
       
    16
        public Socket getS() {
    17
            return s;
    18
        }
    19
     
    20
        public void setS(Socket s) {
    21
            this.s = s;
    22
        }
    23
     
    24
        //构造函数
    25
        public ClientConServerThread(Socket s){
    26
            this.s=s;
    27
        }
    28
       
    29
        public void run(){
    30
            while(true){
    31
                //不停的读取从服务器端发来的消息
    32
                try {
    33
                    ObjectInputStream ois=new ObjectInputStream(s.getInputStream());
    34
                    Message m=(Message)ois.readObject();
    35
                   
    36
                    //按消息包的类型来处理不同的包
    37
                    if(m.getMesType().equals(MessageType.message_comm_mes)){
    38
                        //把从服务器获得的消息,显示到该显示的聊天界面上
    39
                        QqChat qqChat=ManageQqChat.getQqChat(m.getGetder()+" "+m.getSender());
    40
                        //显示
    41
                        qqChat.showMessage(m);
    42
                    }else if(m.getMesType().equals(MessageType.message_ret_onLineFriend)){
    43
                        String con=m.getCon();
    44
                        String []friends=con.split(" ");
    45
                        String getter=m.getGetder();
    46
                        //修改相应的好友列表
    47
                        QqFriendList qqFrindList=ManageQqFriendList.getQqFriendList(getter);
    48
                        //更新在线好友
    49
                        if(qqFrindList!=null){
    50
                            qqFrindList.updateFriend(m);
    51
                        }
    52
                    }
    53
                } catch (Exception e) {
    54
                    e.printStackTrace();
    55
                }
    56
            }
    57
        }
    58
    }

    *******************************************************************************

    [ManageClientConServerThread.java]

    x
     
    1
    /**
    2
     * 这是一个管理客户端与服务器保持通讯的线程类
    3
     */
    4
    package com.qq.client.tools;
    5
     
    6
    import java.util.HashMap;
    7
     
    8
    public class ManageClientConServerThread {
    9
        private static HashMap hm=new HashMap<String, ClientConServerThread>();
    10
        //把创建好的ClientConServerThread放入到hm中
    11
        public static void addClientConServerThread(String qqId,ClientConServerThread ccst){
    12
            hm.put(qqId, ccst);
    13
        }
    14
       
    15
        //可以通过qqId取得该线程
    16
        public static ClientConServerThread getClientConServerThread(String qqId){
    17
            return (ClientConServerThread)hm.get(qqId);
    18
        }
    19
    }
    20






  • 相关阅读:
    mpvue: stylus定义主题色
    mpvue: 单个页面自定义导航栏或隐藏
    mpvue: fsevents is not a constructor
    Nginx:taro h5 Nginx代理配置
    git: 替换remote origin
    taro3.x: h5地图兼容组件封装
    taro3.x: h5地图兼容
    taro3.x: 使用taro-router在H5浏览器返回报错
    taro3.x: tarojs-router
    java线程与线程安全的单例模式
  • 原文地址:https://www.cnblogs.com/xuxaut-558/p/10047918.html
Copyright © 2011-2022 走看看