本文為大家分享了Java多線程實(shí)現(xiàn)多人聊天室功能的具體代碼,供大家參考,具體內(nèi)容如下
1.實(shí)驗(yàn)?zāi)康模?/h3>
編寫一個(gè) Java 應(yīng)用程序,實(shí)現(xiàn)圖形界面多人聊天室(多線程實(shí)現(xiàn)),要求聊天室窗口標(biāo)題是 “歡迎使用 XXX 聊天室應(yīng)用”,其中 XXX 是自己的班級姓名學(xué)號,如“軟件 171 張三 1234”。
2.實(shí)驗(yàn)代碼:
服務(wù)端程序代碼:
ServerChar.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
package works; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; public class ServerChat { //定義Map集合用于存儲(chǔ)用戶的Socket以及用戶的名字 key:Socket Value:用戶名 public final static Map<Socket,String> socketsMaps = Collections.synchronizedMap( new HashMap<Socket,String>()); public static void main(String[] args) { // TODO Auto-generated method stub try { // 創(chuàng)建服務(wù)端套接字 ServerSocket serverSocket = new ServerSocket( 9999 ); System.out.println( "------服務(wù)端暴露-------" ); while ( true ) { // 監(jiān)聽客戶端套接字,若有客戶端連接,則代碼不會(huì)往下執(zhí)行,否則會(huì)堵塞在此處。 Socket socket = serverSocket.accept(); // 開啟線程,用于讀取客戶端發(fā)送的信息,并轉(zhuǎn)發(fā)給每一個(gè)客戶端 new ThreadServer(socket).start(); } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } } class ThreadServer extends Thread { private Socket socket; ThreadServer(){}; ThreadServer(Socket socket) { this .socket = socket; } @Override public void run() { try { while ( true ) { DataInputStream dataInputStream = new DataInputStream(socket.getInputStream()); String data = dataInputStream.readUTF(); if (data.startsWith( "①②③④" )&&data.endsWith( "①②③④" )) { //發(fā)送過來的是用戶名 //將Socket以及用戶名字都存放在Map集合中 ServerChat.socketsMaps.put(socket, data.replace( "①②③④" , "" )); //獲取所有的key(Socket),將所有用戶的名字發(fā)送至客戶端 Set<Socket> sockets = ServerChat.socketsMaps.keySet(); //獲取所有的用戶的名字,將這些名字拼裝成一個(gè)字符串 Collection<String> names = ServerChat.socketsMaps.values(); StringBuffer sbf = new StringBuffer(); for (String userName :names) { sbf.append(userName).append( "," ); } System.out.println( "sbf:" +sbf.toString()); for (Socket soc:sockets) { DataOutputStream dataOutputStream = new DataOutputStream(soc.getOutputStream()); dataOutputStream.writeUTF( "①②③④" +sbf.toString()+ "①②③④" ); dataOutputStream.flush(); } } else { //發(fā)送過來的是聊天信息 //獲取所有的key(Socket),將所有用戶的名字發(fā)送至客戶端 Set<Socket> sockets = ServerChat.socketsMaps.keySet(); //將聊天信息廣播出去 for (Socket soc:sockets) { DataOutputStream dataOutputStream = new DataOutputStream(soc.getOutputStream()); dataOutputStream.writeUTF( "[ " +ServerChat.socketsMaps.get(socket)+ " ]說:" +data); dataOutputStream.flush(); } } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } |
客戶端程序代碼:
ClientChar.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
|
package works; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; public class ClientChat { private JFrame mainWin = new JFrame( "聊天窗口" ); // 消息展示框 private JTextArea displayTa = new JTextArea( 14 , 40 ); // 在線用戶名稱展示框 private DefaultListModel<String> userListModel = new DefaultListModel<>(); private JList<String> userList = new JList<>(userListModel); // 消息發(fā)送框 private JTextArea inputTF = new JTextArea( 4 , 40 ); // 消息按鈕 private JButton sendBn = new JButton( "發(fā)送" ); // 用戶記錄當(dāng)前聊天用戶名 private String curUser; public static void main(String[] args) { new ClientChat().init(); } private void init() { try { // 通過彈出對話框獲取用戶輸入的用戶名 String userName = JOptionPane.showInputDialog(mainWin, "請輸入您的用戶名:" ); // 把用戶輸入的用戶名,賦給curUser curUser = userName; mainWin.setTitle(curUser + "的聊天窗口" ); // 創(chuàng)建套接字 Socket socket = new Socket( "192.168.193.1" , 9999 ); // 向服務(wù)器聲明 DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream()); //發(fā)送用戶名到服務(wù)端 dataOutputStream.writeUTF( "①②③④" +userName+ "①②③④" ); dataOutputStream.flush(); // 開啟線程,用于讀取服務(wù)器發(fā)送的信息 new ThreadClient(socket, this ).start(); JPanel bottomPanel = new JPanel(); // 將消息框和按鈕添加到窗口的底端 mainWin.add(bottomPanel, BorderLayout.SOUTH); bottomPanel.add(inputTF); bottomPanel.add(sendBn); ActionListener listener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // 獲取用戶發(fā)送的消息 String message = inputTF.getText(); sendSms(message,socket); } }; // 給發(fā)送消息按鈕綁定點(diǎn)擊事件監(jiān)聽器 sendBn.addActionListener(listener); JPanel centerPanel = new JPanel(); // 將展示消息區(qū)centerPanel添加到窗口的中間 mainWin.add(centerPanel); // 讓展示消息區(qū)可以滾動(dòng) centerPanel.add( new JScrollPane(displayTa)); displayTa.setEditable( false ); // 用戶列表和是否私聊放到窗口的最右邊 Box rightBox = new Box(BoxLayout.Y_AXIS); userList.setFixedCellWidth( 60 ); userList.setVisibleRowCount( 13 ); rightBox.add( new JLabel( "用戶列表:" )); rightBox.add( new JScrollPane(userList)); centerPanel.add(rightBox); // 關(guān)閉窗口退出當(dāng)前程序 mainWin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainWin.pack(); // swing加上這句就可以擁有關(guān)閉窗口的功能 mainWin.setVisible( true ); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } //點(diǎn)擊發(fā)送后將消息發(fā)送到服務(wù)器 protected void sendSms(String sms, Socket socket) { try { //發(fā)送聊天消息到服務(wù)端 DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream()); dataOutputStream.writeUTF(sms); dataOutputStream.flush(); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } public DefaultListModel<String> getUserListModel() { return userListModel; } public JTextArea getDisplayTa() { return displayTa; } public JTextArea getInputTF() { return inputTF; } } // 定義線程類,用來讀取服務(wù)器發(fā)送的信息 class ThreadClient extends Thread { private Socket socket; private ClientChat clientChat; ThreadClient() { } ThreadClient(Socket socket, ClientChat clientChat) { this .socket = socket; this .clientChat = clientChat; } @Override public void run() { try { while ( true ) { DataInputStream DataInputStream = new DataInputStream(socket.getInputStream()); String message = DataInputStream.readUTF(); if (message.startsWith( "①②③④" )&&message.endsWith( "①②③④" )) { //說明信息是用戶名 String[] names = message.replace( "①②③④" , "" ).split( "," ); // 將用戶列表先清空 clientChat.getUserListModel().clear(); for ( int i = 0 ; i < names.length; ++i) { clientChat.getUserListModel().addElement(names[i]); } } else { //說明是聊天信息,將聊天信息放在displayTa中 clientChat.getInputTF().setText( "" ); clientChat.getDisplayTa().append(message+ "\t\n" ); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } |
3.實(shí)驗(yàn)截圖
先開啟服務(wù)端
再開啟客戶端
聊天過程
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://blog.csdn.net/CHANGE_A1/article/details/111086171