JAVA入門到精通-第92講-山寨QQ專案6-多對多的聊天
阿新 • • 發佈:2018-12-01
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;
---------------------- 給每一個登入賬號分配執行緒;
把通訊的任務交給執行緒類;
---------------------
-多對多聊天 經測試,後臺傳送訊息正常;
--------------- -顯示後臺的訊息到各自的聊天介面
伺服器中轉 2/3號只有一個連線;
接收資訊:while迴圈不停地讀取;
當1號點開兩個視窗時,2/3會共同去爭取這個socket; 會出現流同時併發異常;
Socket處理成static不太合理;
啟動一個視窗就會佔據Socket不放;
------------- -實現真正的多人聊天,互相不出現錯誤
-新的賬號登入,開一個執行緒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()+"\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]
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 ObjectInputS