由于需要制作網絡計算機網絡課程設計,并且不想搞網絡布線或者局域網路由器配置等等這種完全搞不懂的東西,最后決定使用socket基于java編寫一個局域網聊天室:
關于socket以及網絡編程的相關知識詳見我另一篇文章:Java基于socket編程
程序基于C/S結構,即客戶端服務器模式。
服務器:
默認ip為本機ip
需要雙方確定一個端口號
可設置最大連接人數
可啟動與關閉
界面顯示在線用戶人以及姓名(本機不在此顯示)
客戶端:
需要手動設置服務器ip地址(局域網)
手動設置端口號
輸入姓名
可連接可斷開
程序運行界面如下:
服務器:
客戶端:
具體代碼我會在最后上傳。
軟件有很多不足,其中比如:
沒有與數據庫有任何交集
優化:可將所有用戶存放在數據庫中,以及將聊天記錄也放入數據庫中
沒有實現一對一聊天
優化:需重新定義一對一聊天的方法
還有許多不足的地方,日后有興趣再回來慢慢研究
下面為該程序三個代碼:
User.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
|
public class User{ /** * 用戶信息類 * 用于記錄用戶個人信息:姓名以及IP */ private String name; private String ip; public User(String name, String ip) { this .name = name; this .ip = ip; } public String getName() { return name; } public void setName(String name) { this .name = name; } public String getIp() { return ip; } public void setIp(String ip) { this .ip = ip; } } |
Server_more.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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
|
import java.awt.BorderLayout; import java.awt.Color; import java.awt.GridLayout; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.BindException; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.StringTokenizer; 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.JSplitPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.border.TitledBorder; public class Server_more { private JFrame frame; private JTextArea contentArea; //文本域 private JTextField txt_message; //用于顯示文本信息 private JTextField txt_max; //設置最大連接人數 private JTextField txt_port; //設置端口號 private JButton btn_start; //開始按鈕 private JButton btn_stop; //斷開按鈕 private JButton btn_send; //發送按鈕 private JPanel northPanel; //北方面板 private JPanel southPanel; //南方面板 private JScrollPane rightPanel; //左邊滾動條 private JScrollPane leftPanel; //右邊滾動條 private JSplitPane centerSplit; //分割線 private JList userList; //列表組件 private DefaultListModel listModel; private ServerSocket serverSocket; private ServerThread serverThread; private ArrayList<ClientThread> clients; private boolean isStart = false ; // 主方法,程序執行入口 public static void main(String[] args) { new Server_more(); } // 執行消息發送 public void send() { if (!isStart) { JOptionPane.showMessageDialog(frame, "服務器還未啟動,不能發送消息!" , "錯誤" , JOptionPane.ERROR_MESSAGE); return ; } if (clients.size() == 0 ) { JOptionPane.showMessageDialog(frame, "沒有用戶在線,不能發送消息!" , "錯誤" , JOptionPane.ERROR_MESSAGE); return ; } String message = txt_message.getText().trim(); if (message == null || message.equals( "" )) { JOptionPane.showMessageDialog(frame, "消息不能為空!" , "錯誤" , JOptionPane.ERROR_MESSAGE); return ; } sendServerMessage(message); // 群發服務器消息 contentArea.append( "服務器:" + txt_message.getText() + "\r\n" ); txt_message.setText( null ); } // 構造放法 public Server_more() { frame = new JFrame( "服務器" ); // 更改JFrame的圖標: //frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Client.class.getResource("qq.png"))); //frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Server.class.getResource("qq.png"))); contentArea = new JTextArea(); contentArea.setEditable( false ); contentArea.setForeground(Color.blue); txt_message = new JTextField(); txt_max = new JTextField( "30" ); txt_port = new JTextField( "6666" ); btn_start = new JButton( "啟動" ); btn_stop = new JButton( "停止" ); btn_send = new JButton( "發送" ); btn_stop.setEnabled( false ); listModel = new DefaultListModel(); userList = new JList(listModel); southPanel = new JPanel( new BorderLayout()); southPanel.setBorder( new TitledBorder( "寫消息" )); southPanel.add(txt_message, "Center" ); southPanel.add(btn_send, "East" ); leftPanel = new JScrollPane(userList); leftPanel.setBorder( new TitledBorder( "在線用戶" )); rightPanel = new JScrollPane(contentArea); rightPanel.setBorder( new TitledBorder( "消息顯示區" )); centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, rightPanel); centerSplit.setDividerLocation( 100 ); northPanel = new JPanel(); northPanel.setLayout( new GridLayout( 1 , 6 )); northPanel.add( new JLabel( "人數上限" )); northPanel.add(txt_max); northPanel.add( new JLabel( "端口" )); northPanel.add(txt_port); northPanel.add(btn_start); northPanel.add(btn_stop); northPanel.setBorder( new TitledBorder( "配置信息" )); frame.setLayout( new BorderLayout()); frame.add(northPanel, "North" ); frame.add(centerSplit, "Center" ); frame.add(southPanel, "South" ); frame.setSize( 600 , 400 ); //frame.setSize(Toolkit.getDefaultToolkit().getScreenSize());//設置全屏 int screen_width = Toolkit.getDefaultToolkit().getScreenSize().width; int screen_height = Toolkit.getDefaultToolkit().getScreenSize().height; frame.setLocation((screen_width - frame.getWidth()) / 2 , (screen_height - frame.getHeight()) / 2 ); frame.setVisible( true ); // 關閉窗口時事件 frame.addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { if (isStart) { closeServer(); // 關閉服務器 } System.exit( 0 ); // 退出程序 } }); // 文本框按回車鍵時事件 txt_message.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { send(); } }); // 單擊發送按鈕時事件 btn_send.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent arg0) { send(); } }); // 單擊啟動服務器按鈕時事件 btn_start.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { if (isStart) { JOptionPane.showMessageDialog(frame, "服務器已處于啟動狀態,不要重復啟動!" , "錯誤" , JOptionPane.ERROR_MESSAGE); return ; } int max; int port; try { try { max = Integer.parseInt(txt_max.getText()); } catch (Exception e1) { throw new Exception( "人數上限為正整數!" ); } if (max <= 0 ) { throw new Exception( "人數上限為正整數!" ); } try { port = Integer.parseInt(txt_port.getText()); } catch (Exception e1) { throw new Exception( "端口號為正整數!" ); } if (port <= 0 ) { throw new Exception( "端口號 為正整數!" ); } serverStart(max, port); contentArea.append( "服務器已成功啟動!人數上限:" + max + ",端口:" + port + "\r\n" ); JOptionPane.showMessageDialog(frame, "服務器成功啟動!" ); btn_start.setEnabled( false ); txt_max.setEnabled( false ); txt_port.setEnabled( false ); btn_stop.setEnabled( true ); } catch (Exception exc) { JOptionPane.showMessageDialog(frame, exc.getMessage(), "錯誤" , JOptionPane.ERROR_MESSAGE); } } }); // 單擊停止服務器按鈕時事件 btn_stop.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { if (!isStart) { JOptionPane.showMessageDialog(frame, "服務器還未啟動,無需停止!" , "錯誤" , JOptionPane.ERROR_MESSAGE); return ; } try { closeServer(); btn_start.setEnabled( true ); txt_max.setEnabled( true ); txt_port.setEnabled( true ); btn_stop.setEnabled( false ); contentArea.append( "服務器成功停止!\r\n" ); JOptionPane.showMessageDialog(frame, "服務器成功停止!" ); } catch (Exception exc) { JOptionPane.showMessageDialog(frame, "停止服務器發生異常!" , "錯誤" , JOptionPane.ERROR_MESSAGE); } } }); } // 啟動服務器 public void serverStart( int max, int port) throws java.net.BindException { try { clients = new ArrayList<ClientThread>(); serverSocket = new ServerSocket(port); serverThread = new ServerThread(serverSocket, max); serverThread.start(); isStart = true ; } catch (BindException e) { isStart = false ; throw new BindException( "端口號已被占用,請換一個!" ); } catch (Exception e1) { e1.printStackTrace(); isStart = false ; throw new BindException( "啟動服務器異常!" ); } } // 關閉服務器 @SuppressWarnings ( "deprecation" ) public void closeServer() { try { if (serverThread != null ) serverThread.stop(); // 停止服務器線程 for ( int i = clients.size() - 1 ; i >= 0 ; i--) { // 給所有在線用戶發送關閉命令 clients.get(i).getWriter().println( "CLOSE" ); clients.get(i).getWriter().flush(); // 釋放資源 clients.get(i).stop(); // 停止此條為客戶端服務的線程 clients.get(i).reader.close(); clients.get(i).writer.close(); clients.get(i).socket.close(); clients.remove(i); } if (serverSocket != null ) { serverSocket.close(); // 關閉服務器端連接 } listModel.removeAllElements(); // 清空用戶列表 isStart = false ; } catch (IOException e) { e.printStackTrace(); isStart = true ; } } // 群發服務器消息 public void sendServerMessage(String message) { for ( int i = clients.size() - 1 ; i >= 0 ; i--) { clients.get(i).getWriter().println( "服務器:" + message + "(多人發送)" ); clients.get(i).getWriter().flush(); } } // 服務器線程 class ServerThread extends Thread { private ServerSocket serverSocket; private int max; // 人數上限 // 服務器線程的構造方法 public ServerThread(ServerSocket serverSocket, int max) { this .serverSocket = serverSocket; this .max = max; } public void run() { while ( true ) { // 不停的等待客戶端的鏈接 try { Socket socket = serverSocket.accept(); if (clients.size() == max) { // 如果已達人數上限 BufferedReader r = new BufferedReader( new InputStreamReader(socket.getInputStream())); PrintWriter w = new PrintWriter(socket .getOutputStream()); // 接收客戶端的基本用戶信息 String inf = r.readLine(); StringTokenizer st = new StringTokenizer(inf, "@" ); User user = new User(st.nextToken(), st.nextToken()); // 反饋連接成功信息 w.println( "MAX@服務器:對不起," + user.getName() + user.getIp() + ",服務器在線人數已達上限,請稍后嘗試連接!" ); w.flush(); // 釋放資源 r.close(); w.close(); socket.close(); continue ; } ClientThread client = new ClientThread(socket); client.start(); // 開啟對此客戶端服務的線程 clients.add(client); listModel.addElement(client.getUser().getName()); // 更新在線列表 contentArea.append(client.getUser().getName() + client.getUser().getIp() + "上線!\r\n" ); } catch (IOException e) { e.printStackTrace(); } } } } // 為一個客戶端服務的線程 class ClientThread extends Thread { private Socket socket; private BufferedReader reader; private PrintWriter writer; private User user; public BufferedReader getReader() { return reader; } public PrintWriter getWriter() { return writer; } public User getUser() { return user; } // 客戶端線程的構造方法 public ClientThread(Socket socket) { try { this .socket = socket; reader = new BufferedReader( new InputStreamReader(socket .getInputStream())); writer = new PrintWriter(socket.getOutputStream()); // 接收客戶端的基本用戶信息 String inf = reader.readLine(); StringTokenizer st = new StringTokenizer(inf, "@" ); user = new User(st.nextToken(), st.nextToken()); // 反饋連接成功信息 writer.println(user.getName() + user.getIp() + "與服務器連接成功!" ); writer.flush(); // 反饋當前在線用戶信息 if (clients.size() > 0 ) { String temp = "" ; for ( int i = clients.size() - 1 ; i >= 0 ; i--) { temp += (clients.get(i).getUser().getName() + "/" + clients .get(i).getUser().getIp()) + "@" ; } writer.println( "USERLIST@" + clients.size() + "@" + temp); writer.flush(); } // 向所有在線用戶發送該用戶上線命令 for ( int i = clients.size() - 1 ; i >= 0 ; i--) { clients.get(i).getWriter().println( "ADD@" + user.getName() + user.getIp()); clients.get(i).getWriter().flush(); } } catch (IOException e) { e.printStackTrace(); } } @SuppressWarnings ( "deprecation" ) public void run() { // 不斷接收客戶端的消息,進行處理。 String message = null ; while ( true ) { try { message = reader.readLine(); // 接收客戶端消息 if (message.equals( "CLOSE" )) // 下線命令 { contentArea.append( this .getUser().getName() + this .getUser().getIp() + "下線!\r\n" ); // 斷開連接釋放資源 reader.close(); writer.close(); socket.close(); // 向所有在線用戶發送該用戶的下線命令 for ( int i = clients.size() - 1 ; i >= 0 ; i--) { clients.get(i).getWriter().println( "DELETE@" + user.getName()); clients.get(i).getWriter().flush(); } listModel.removeElement(user.getName()); // 更新在線列表 // 刪除此條客戶端服務線程 for ( int i = clients.size() - 1 ; i >= 0 ; i--) { if (clients.get(i).getUser() == user) { ClientThread temp = clients.get(i); clients.remove(i); // 刪除此用戶的服務線程 temp.stop(); // 停止這條服務線程 return ; } } } else { dispatcherMessage(message); // 轉發消息 } } catch (IOException e) { e.printStackTrace(); } } } // 轉發消息 public void dispatcherMessage(String message) { StringTokenizer stringTokenizer = new StringTokenizer(message, "@" ); String source = stringTokenizer.nextToken(); String owner = stringTokenizer.nextToken(); String content = stringTokenizer.nextToken(); message = source + ":" + content; contentArea.append(message + "\r\n" ); if (owner.equals( "ALL" )) { // 群發 for ( int i = clients.size() - 1 ; i >= 0 ; i--) { clients.get(i).getWriter().println(message + "(多人發送)" ); clients.get(i).getWriter().flush(); } } } } } |
Client_more.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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
|
import java.awt.BorderLayout; import java.awt.Color; import java.awt.GridLayout; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; 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.JSplitPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.border.TitledBorder; public class Client_more{ private JFrame frame; private JList userList; private JTextArea textArea; private JTextField textField; private JTextField txt_port; private JTextField txt_hostIp; private JTextField txt_name; private JButton btn_start; private JButton btn_stop; private JButton btn_send; private JPanel northPanel; private JPanel southPanel; private JScrollPane rightScroll; private JScrollPane leftScroll; private JSplitPane centerSplit; private DefaultListModel listModel; private boolean isConnected = false ; private Socket socket; private PrintWriter writer; private BufferedReader reader; private MessageThread messageThread; // 負責接收消息的線程 private Map<String, User> onLineUsers = new HashMap<String, User>(); // 所有在線用戶 // 主方法,程序入口 public static void main(String[] args) { new Client_more(); } // 執行發送 public void send() { if (!isConnected) { JOptionPane.showMessageDialog(frame, "還沒有連接服務器,無法發送消息!" , "錯誤" , JOptionPane.ERROR_MESSAGE); return ; } String message = textField.getText().trim(); if (message == null || message.equals( "" )) { JOptionPane.showMessageDialog(frame, "消息不能為空!" , "錯誤" , JOptionPane.ERROR_MESSAGE); return ; } sendMessage(frame.getTitle() + "@" + "ALL" + "@" + message); textField.setText( null ); } // 構造方法 public Client_more() { textArea = new JTextArea(); textArea.setEditable( false ); textArea.setForeground(Color.blue); textField = new JTextField(); txt_port = new JTextField( "6666" ); txt_hostIp = new JTextField( "127.0.0.1" ); txt_name = new JTextField( "吳承潛" ); btn_start = new JButton( "連接" ); btn_stop = new JButton( "斷開" ); btn_send = new JButton( "發送" ); listModel = new DefaultListModel(); userList = new JList(listModel); northPanel = new JPanel(); northPanel.setLayout( new GridLayout( 1 , 7 )); northPanel.add( new JLabel( "端口" )); northPanel.add(txt_port); northPanel.add( new JLabel( "服務器IP" )); northPanel.add(txt_hostIp); northPanel.add( new JLabel( "姓名" )); northPanel.add(txt_name); northPanel.add(btn_start); northPanel.add(btn_stop); northPanel.setBorder( new TitledBorder( "連接信息" )); rightScroll = new JScrollPane(textArea); rightScroll.setBorder( new TitledBorder( "消息顯示區" )); leftScroll = new JScrollPane(userList); leftScroll.setBorder( new TitledBorder( "在線用戶" )); southPanel = new JPanel( new BorderLayout()); southPanel.add(textField, "Center" ); southPanel.add(btn_send, "East" ); southPanel.setBorder( new TitledBorder( "寫消息" )); centerSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftScroll, rightScroll); centerSplit.setDividerLocation( 100 ); frame = new JFrame( "客戶機" ); // 更改JFrame的圖標: // frame.setIconImage(Toolkit.getDefaultToolkit().createImage(Client.class.getResource("qq.png"))); frame.setLayout( new BorderLayout()); frame.add(northPanel, "North" ); frame.add(centerSplit, "Center" ); frame.add(southPanel, "South" ); frame.setSize( 600 , 400 ); int screen_width = Toolkit.getDefaultToolkit().getScreenSize().width; int screen_height = Toolkit.getDefaultToolkit().getScreenSize().height; frame.setLocation((screen_width - frame.getWidth()) / 2 , (screen_height - frame.getHeight()) / 2 ); frame.setVisible( true ); // 寫消息的文本框中按回車鍵時事件 textField.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent arg0) { send(); } }); // 單擊發送按鈕時事件 btn_send.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { send(); } }); // 單擊連接按鈕時事件 btn_start.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { int port; if (isConnected) { JOptionPane.showMessageDialog(frame, "已處于連接上狀態,不要重復連接!" , "錯誤" , JOptionPane.ERROR_MESSAGE); return ; } try { try { port = Integer.parseInt(txt_port.getText().trim()); } catch (NumberFormatException e2) { throw new Exception( "端口號不符合要求!端口為整數!" ); } String hostIp = txt_hostIp.getText().trim(); String name = txt_name.getText().trim(); if (name.equals( "" ) || hostIp.equals( "" )) { throw new Exception( "姓名、服務器IP不能為空!" ); } boolean flag = connectServer(port, hostIp, name); if (flag == false ) { throw new Exception( "與服務器連接失敗!" ); } frame.setTitle(name); JOptionPane.showMessageDialog(frame, "成功連接!" ); } catch (Exception exc) { JOptionPane.showMessageDialog(frame, exc.getMessage(), "錯誤" , JOptionPane.ERROR_MESSAGE); } } }); // 單擊斷開按鈕時事件 btn_stop.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { if (!isConnected) { JOptionPane.showMessageDialog(frame, "已處于斷開狀態,不要重復斷開!" , "錯誤" , JOptionPane.ERROR_MESSAGE); return ; } try { boolean flag = closeConnection(); // 斷開連接 if (flag == false ) { throw new Exception( "斷開連接發生異常!" ); } JOptionPane.showMessageDialog(frame, "成功斷開!" ); } catch (Exception exc) { JOptionPane.showMessageDialog(frame, exc.getMessage(), "錯誤" , JOptionPane.ERROR_MESSAGE); } } }); // 關閉窗口時事件 frame.addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { if (isConnected) { closeConnection(); // 關閉連接 } System.exit( 0 ); // 退出程序 } }); } /** * 連接服務器 * * @param port * @param hostIp * @param name */ public boolean connectServer( int port, String hostIp, String name) { // 連接服務器 try { socket = new Socket(hostIp, port); // 根據端口號和服務器ip建立連接 writer = new PrintWriter(socket.getOutputStream()); reader = new BufferedReader( new InputStreamReader(socket .getInputStream())); // 發送客戶端用戶基本信息(用戶名和ip地址) sendMessage(name + "@" + socket.getLocalAddress().toString()); // 開啟接收消息的線程 messageThread = new MessageThread(reader, textArea); messageThread.start(); isConnected = true ; // 已經連接上了 return true ; } catch (Exception e) { textArea.append( "與端口號為:" + port + " IP地址為:" + hostIp + " 的服務器連接失敗!" + "\r\n" ); isConnected = false ; // 未連接上 return false ; } } /** * 發送消息 * * @param message */ public void sendMessage(String message) { writer.println(message); writer.flush(); } /** * 客戶端主動關閉連接 */ @SuppressWarnings ( "deprecation" ) public synchronized boolean closeConnection() { try { sendMessage( "CLOSE" ); // 發送斷開連接命令給服務器 messageThread.stop(); // 停止接受消息線程 // 釋放資源 if (reader != null ) { reader.close(); } if (writer != null ) { writer.close(); } if (socket != null ) { socket.close(); } isConnected = false ; return true ; } catch (IOException e1) { e1.printStackTrace(); isConnected = true ; return false ; } } // 不斷接收消息的線程 class MessageThread extends Thread { private BufferedReader reader; private JTextArea textArea; // 接收消息線程的構造方法 public MessageThread(BufferedReader reader, JTextArea textArea) { this .reader = reader; this .textArea = textArea; } // 被動的關閉連接 public synchronized void closeCon() throws Exception { // 清空用戶列表 listModel.removeAllElements(); // 被動的關閉連接釋放資源 if (reader != null ) { reader.close(); } if (writer != null ) { writer.close(); } if (socket != null ) { socket.close(); } isConnected = false ; // 修改狀態為斷開 } public void run() { String message = "" ; while ( true ) { try { message = reader.readLine(); StringTokenizer stringTokenizer = new StringTokenizer( message, "/@" ); String command = stringTokenizer.nextToken(); // 命令 if (command.equals( "CLOSE" )) // 服務器已關閉命令 { textArea.append( "服務器已關閉!\r\n" ); closeCon(); // 被動的關閉連接 return ; // 結束線程 } else if (command.equals( "ADD" )) { // 有用戶上線更新在線列表 String username = "" ; String userIp = "" ; if ((username = stringTokenizer.nextToken()) != null && (userIp = stringTokenizer.nextToken()) != null ) { User user = new User(username, userIp); onLineUsers.put(username, user); listModel.addElement(username); } } else if (command.equals( "DELETE" )) { // 有用戶下線更新在線列表 String username = stringTokenizer.nextToken(); User user = (User) onLineUsers.get(username); onLineUsers.remove(user); listModel.removeElement(username); } else if (command.equals( "USERLIST" )) { // 加載在線用戶列表 int size = Integer .parseInt(stringTokenizer.nextToken()); String username = null ; String userIp = null ; for ( int i = 0 ; i < size; i++) { username = stringTokenizer.nextToken(); userIp = stringTokenizer.nextToken(); User user = new User(username, userIp); onLineUsers.put(username, user); listModel.addElement(username); } } else if (command.equals( "MAX" )) { // 人數已達上限 textArea.append(stringTokenizer.nextToken() + stringTokenizer.nextToken() + "\r\n" ); closeCon(); // 被動的關閉連接 JOptionPane.showMessageDialog(frame, "服務器緩沖區已滿!" , "錯誤" , JOptionPane.ERROR_MESSAGE); return ; // 結束線程 } else { // 普通消息 textArea.append(message + "\r\n" ); } } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } } } } |
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。