1. 程式人生 > >JAVA入門到精通-第92講-山寨QQ項目6-多對多的聊天

JAVA入門到精通-第92講-山寨QQ項目6-多對多的聊天

不同的 llc data- cli 界面 shm tool 出現 per

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]

110110 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()+"\r\n";
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
                    + "\r\n");
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()+"\r\n";
104
    // jta.append(info);
105
    // } catch (Exception e) {
106
    // e.printStackTrace();
107
    // }
108
    // }
109
    // }
110
}

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

com.qq.client.model

[QqClienConServer.java]

5454 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]

1515 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]

5858 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




來自為知筆記(Wiz)

JAVA入門到精通-第92講-山寨QQ項目6-多對多的聊天