本文實(shí)例為大家分享了讀取用戶登入出日志并上傳服務(wù)端的具體實(shí)現(xiàn)代碼,供大家參考,具體內(nèi)容如下
該客戶端運(yùn)行在給用戶提供unix服務(wù)的服務(wù)器上。用來(lái)讀取并收集該服務(wù)器上用戶的上下線信息,并進(jìn)行配對(duì)整理后發(fā)送給服務(wù)端匯總。
具體實(shí)現(xiàn)代碼:
1. DMSServer.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
|
package com.dms; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; /** * DMS服務(wù)端,用來(lái)接收每個(gè)客戶端發(fā)送過(guò)來(lái)的 * 配對(duì)日志并保存在本地文件中 * @author Administrator * */ public class DMSServer { //屬性定義 //用來(lái)接收客戶端連接的服務(wù)端的ServerSocket private ServerSocket server; //用來(lái)管理處理客戶端請(qǐng)求的線程的線程池 private ExecutorService threadPool; //保存所有客戶端發(fā)送過(guò)來(lái)配對(duì)日志的文件 private File serverLogFile; //消息隊(duì)列 private BlockingQueue<String> messageQueue = new LinkedBlockingQueue<String>(); public DMSServer() throws Exception{ try { System.out.println( "服務(wù)端正在初始化..." ); //1 解析配置文件server-config.xml Map<String,String> config = loadConfig(); //2 根據(jù)配置文件內(nèi)容初始化屬性 init(config); System.out.println( "服務(wù)端初始化完畢..." ); } catch (Exception e) { System.out.println( "初始化服務(wù)端失敗!" ); throw e; } } /** * 構(gòu)造方法初始化第一步,解析配置文件 * @return 返回的Map中保存的是配置文件中的 * 每一條內(nèi)容,其中key:標(biāo)簽的名字, * value為標(biāo)簽中間的文本 * @throws Exception */ private Map<String,String> loadConfig() throws Exception{ try { SAXReader reader = new SAXReader(); Document doc = reader.read( new File( "server-config.xml" )); Element root = doc.getRootElement(); Map<String,String> config = new HashMap<String,String>(); /* * 獲取<config>標(biāo)簽中的所有子標(biāo)簽 * 并將每一個(gè)子標(biāo)簽的名字作為key,中間的 * 文本作為value存入Map集合 */ List<Element> list = root.elements(); for(Element e : list){ String key = e.getName(); String value = e.getTextTrim(); config.put(key, value); } return config; } catch (Exception e) { System.out.println("解析配置文件異常!"); e.printStackTrace(); throw e; } } /** * 構(gòu)造方法初始化第二步,根據(jù)配置項(xiàng)初始化屬性 * @param config * @throws Exception */ private void init(Map<String,String> config) throws Exception{ /* * 用配置文件中的<logrecfile>初始化屬性:serverLogFile * 用配置文件中的<threadsum>初始化屬性:threadPool,這里創(chuàng)建固定大小線程池。該值作為線程池線程數(shù)量 * 用配置文件中的<serverport>初始化屬性:server,這里這個(gè)值為ServerSocket的服務(wù)端口 */ this.server = new ServerSocket( Integer.parseInt(config.get("serverport")) ); this.serverLogFile = new File( config.get("logrecfile") ); this.threadPool = Executors.newFixedThreadPool( Integer.parseInt(config.get("threadsum")) ); } /** * 服務(wù)端開(kāi)始工作的方法 * @throws Exception */ public void start() throws Exception{ /* * 實(shí)現(xiàn)要求: * 首先單獨(dú)啟動(dòng)一個(gè)線程,用來(lái)運(yùn)行SaveLogHandler * 這個(gè)任務(wù),目的是保存所有配對(duì)日志 * 然后開(kāi)始循環(huán)監(jiān)聽(tīng)服務(wù)端端口,一旦一個(gè)客戶端連接了, * 就實(shí)例化一個(gè)ClientHander,然后將該任務(wù)交給線程池 * 使其分配線程來(lái)處理與該客戶端的交互。 * */ try { System.out.println("服務(wù)端開(kāi)始工作..."); SaveLogHandler slh=new SaveLogHandler(); new Thread(slh).start(); while(true){ Socket socket=server.accept(); threadPool.execute(new ClientHandler(socket)); } } catch (Exception e) { e.printStackTrace(); throw e; } } public static void main(String[] args) { try { DMSServer server = new DMSServer(); server.start(); } catch (Exception e) { System.out.println("啟動(dòng)服務(wù)端失敗!"); } } /** * 該線程負(fù)責(zé)從消息隊(duì)列中取出每一條配對(duì)日志, * 并存入到serverLogFile文件 * @author Administrator * */ private class SaveLogHandler implements Runnable{ public void run(){ PrintWriter pw = null; try { pw = new PrintWriter( new FileOutputStream( serverLogFile,true ) ); while(true){ if(messageQueue.size()>0){ pw.println(messageQueue.poll()); }else{ pw.flush(); Thread.sleep(500); } } } catch (Exception e) { e.printStackTrace(); } finally{ if(pw != null){ pw.close(); } } } } /** * 處理一個(gè)指定客戶端請(qǐng)求 * @author Administrator * */ private class ClientHandler implements Runnable{ private Socket socket; public ClientHandler(Socket socket){ this.socket = socket; } public void run(){ /* * 思路: * 首先接收客戶端發(fā)送過(guò)來(lái)的所有配對(duì)日志, * 直到讀取到"OVER"為止,然后將這些配對(duì) * 日志保存到本地的文件中,并回復(fù)客戶端 * "OK" * 執(zhí)行步驟: * 1:通過(guò)Socket創(chuàng)建輸出流,用來(lái)給客戶端 * 發(fā)送響應(yīng) * 2:通過(guò)Socket創(chuàng)建輸入流,讀取客戶端發(fā)送 * 過(guò)來(lái)的日志 * 3:循環(huán)讀取客戶端發(fā)送過(guò)來(lái)的每一行字符串,并 * 先判斷是否為字符串"OVER",若不是,則是 * 一條配對(duì)日志,那么保存到本地文件,若是, * 則停止讀取。 * 4:成功讀取所有日志后回復(fù)客戶端"OK" */ PrintWriter pw = null ; try { //1 pw = new PrintWriter( new OutputStreamWriter( socket.getOutputStream(), "UTF-8" ) ); //2 BufferedReader br = new BufferedReader( new InputStreamReader( socket.getInputStream(), "UTF-8" ) ); //3 String message = null ; while ((message = br.readLine())!= null ){ if ( "OVER" .equals(message)){ break ; } //將該日志寫(xiě)入文件保存 messageQueue.offer(message); } //4 pw.println( "OK" ); pw.flush(); } catch (Exception e) { e.printStackTrace(); pw.println( "ERROR" ); pw.flush(); } finally { try { //與客戶端斷開(kāi)連接釋放資源 socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } } |
2. DMSClient.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
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
|
package com.dms; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.RandomAccessFile; import java.net.Socket; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; import com.dms.bo.LogData; import com.dms.bo.LogRec; /** * 該客戶端運(yùn)行在給用戶提供unix服務(wù)的服務(wù)器上。 * 用來(lái)讀取并收集該服務(wù)器上用戶的上下線信息,并 * 進(jìn)行配對(duì)整理后發(fā)送給服務(wù)端匯總。 * @author Administrator * */ public class DMSClient { //屬性定義 //第一步:解析日志所需屬性 //unix系統(tǒng)日志文件 private File logFile; //保存解析后日志的文件 private File textLogFile; //書(shū)簽文件 private File lastPositionFile; //每次解析日志的條目數(shù) private int batch; //第二步:配對(duì)日志所需要屬性 //保存配對(duì)日志的文件 private File logRecFile; //保存未配對(duì)日志的文件 private File loginLogFile; //第三步:發(fā)送日志所需要屬性 //服務(wù)端地址 private String serverHost; //服務(wù)端端口 private int serverPort; /** * 構(gòu)造方法,用來(lái)初始化客戶端 * @throws Exception */ public DMSClient() throws Exception{ try { //1 解析配置文件config.xml Map<String,String> config = loadConfig(); //打樁 System.out.println(config); //2 根據(jù)配置文件內(nèi)容初始化屬性 init(config); } catch (Exception e) { System.out.println( "初始化失敗!" ); throw e; } } /** * 構(gòu)造方法初始化第二步,根據(jù)配置項(xiàng)初始化屬性 * @param config * @throws Exception */ private void init(Map<String,String> config) throws Exception{ try { logFile = new File( config.get( "logfile" ) ); textLogFile = new File( config.get( "textlogfile" ) ); lastPositionFile = new File( config.get( "lastpositionfile" ) ); batch = Integer.parseInt( config.get( "batch" ) ); logRecFile = new File( config.get( "logrecfile" ) ); loginLogFile = new File( config.get( "loginlogfile" ) ); serverHost = config.get( "serverhost" ); serverPort = Integer.parseInt( config.get( "serverport" ) ); } catch (Exception e) { System.out.println( "初始化屬性失敗!" ); e.printStackTrace(); throw e; } } /** * 構(gòu)造方法初始化第一步,解析配置文件 * @return 返回的Map中保存的是配置文件中的 * 每一條內(nèi)容,其中key:標(biāo)簽的名字, * value為標(biāo)簽中間的文本 * @throws Exception */ private Map<String,String> loadConfig() throws Exception{ try { SAXReader reader = new SAXReader(); Document doc = reader.read( new File( "config.xml" )); Element root = doc.getRootElement(); Map<String,String> config = new HashMap<String,String>(); /* * 獲取<config>標(biāo)簽中的所有子標(biāo)簽 * 并將每一個(gè)子標(biāo)簽的名字作為key,中間的 * 文本作為value存入Map集合 */ List<Element> list = root.elements(); for(Element e : list){ String key = e.getName(); String value = e.getTextTrim(); config.put(key, value); } return config; } catch (Exception e) { System.out.println("解析配置文件異常!"); e.printStackTrace(); throw e; } } /** * 客戶端開(kāi)始工作的方法 * 循環(huán)執(zhí)行三步: * 1:解析日志 * 2:配對(duì)日志 * 3:發(fā)送日志 */ public void start(){ parseLogs(); matchLogs(); sendLogs(); // while(true){ // //解析日志 // if(!parseLogs()){ // continue; // } // //配對(duì)日志 // if(!matchLogs()){ // continue; // } // //發(fā)送日志 // sendLogs(); // } } /** * 第三步:發(fā)送日志 * @return true:發(fā)送成功 * false:發(fā)送失敗 */ private boolean sendLogs(){ /* * 實(shí)現(xiàn)思路: * 將logRecFile文件中的所有配對(duì)日志讀取 * 出來(lái)然后連接上服務(wù)端并發(fā)送過(guò)去,若服務(wù)端 * 全部接收,就可以將該文件刪除,表示發(fā)送 * 完畢了。 * 實(shí)現(xiàn)步驟: * 1:logRecFile文件必須存在 * 2:將所有配對(duì)日志讀取出來(lái)并存入一個(gè)集合 * 等待發(fā)送 * 3:通過(guò)Socket連接服務(wù)端 * 4:創(chuàng)建輸出流 * 5:順序?qū)⑺信鋵?duì)日志按行發(fā)送給服務(wù)端 * 6:單獨(dú)發(fā)送一個(gè)字符串"OVER"表示所有日志 * 均已發(fā)送完畢 * 7:創(chuàng)建輸入流 * 8:讀取服務(wù)端發(fā)送回來(lái)的響應(yīng)字符串 * 9:若響應(yīng)的字符串為"OK",表示服務(wù)端正常 * 接收了所有日志,這時(shí)就可以將logRecFile * 文件刪除并返回true表示發(fā)送完畢。 * */ Socket socket = null; try { //1 if(!logRecFile.exists()){ System.out.println(logRecFile+"不存在!"); return false; } //2 List<String> matches = IOUtil.loadLogRec(logRecFile); //3 socket = new Socket(serverHost,serverPort); //4 PrintWriter pw = new PrintWriter( new OutputStreamWriter( socket.getOutputStream(),"UTF-8" ) ); //5 for(String log : matches){ pw.println(log); } //6 pw.println("OVER"); pw.flush(); //7 BufferedReader br = new BufferedReader( new InputStreamReader( socket.getInputStream(),"UTF-8" ) ); //8 String response = br.readLine(); //9 if("OK".equals(response)){ logRecFile.delete(); return true; }else{ System.out.println("發(fā)送日志失敗!"); return false; } } catch (Exception e) { System.out.println("發(fā)送日志失敗!"); e.printStackTrace(); } finally{ if(socket != null){ try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } return false; } /** * 第二步:配對(duì)日志 * @return true:配對(duì)成功 * false:配對(duì)失敗 */ private boolean matchLogs(){ /* * 實(shí)現(xiàn)思路: * 將第一步解析的新日志,與上次為配對(duì)成功 * 的登入日志全部讀取出來(lái),然后再按照user, * pid相同,type一個(gè)是7,一個(gè)是8進(jìn)行配對(duì)。 * 只要能找到類(lèi)型為8的,一定可以找到一個(gè) * 能與之配對(duì)的登入日志。 * * 實(shí)現(xiàn)步驟: * 1:必要的判斷 * 1.1:logRecFile是否存在,存在則不再 * 進(jìn)行新的配對(duì)工作,避免覆蓋。 * 1.2:textLogFile文件必須存在。 * 2:讀取textLogFile將日志讀取出來(lái),并 * 存入到集合中。(若干LogData實(shí)例) * 3:若loginLogFile文件若存在,則說(shuō)明 * 有上次未配對(duì)成功的日志,也將其讀取 * 出來(lái)存入集合等待一起配對(duì) * 4:配對(duì)工作 * 4.1:創(chuàng)建一個(gè)集合,用于保存所有配對(duì)日志 * 4.2:創(chuàng)建兩個(gè)Map分別保存登入日志與登出日志 * 4.3:遍歷所有待配對(duì)的日志,按照登入與登出 * 分別存入兩個(gè)Map中, * 其中key:user,pid * value:LogData實(shí)例 * 4.4:遍歷登出Map,并根據(jù)每條登出日志的key * 去登入Map中找到對(duì)應(yīng)的登入日志,并 * 以一個(gè)LogRec實(shí)例保存該配對(duì)日志,然后 * 存入配對(duì)日志的集合中。并將該配對(duì)日志 * 中的登入日志從登入Map中刪除。這樣一來(lái) * 登入Map中應(yīng)當(dāng)只剩下沒(méi)有配對(duì)的了。 * 5:將配對(duì)日志寫(xiě)入到logRecFile中 * 6:將所有未配對(duì)日志寫(xiě)入到loginLogFile中 * 7:將textLogFile文件刪除 * 8:返回true,表示配對(duì)完畢 * */ try { //1 //1.1 if(logRecFile.exists()){ return true; } //1.2 if(!textLogFile.exists()){ System.out.println(textLogFile+"不存在!"); return false; } //2 List<LogData> list = IOUtil.loadLogData(textLogFile); //3 if(loginLogFile.exists()){ list.addAll( IOUtil.loadLogData(loginLogFile) ); } //4 //4.1 List<LogRec> matches = new ArrayList<LogRec>(); //4.2 Map<String,LogData> loginMap = new HashMap<String,LogData>(); Map<String,LogData> logoutMap = new HashMap<String,LogData>(); //4.3 for(LogData logData : list){ String key = logData.getUser()+","+ logData.getPid(); if(logData.getType()==LogData.TYPE_LOGIN){ loginMap.put(key, logData); }else if(logData.getType()==LogData.TYPE_LOGOUT){ logoutMap.put(key, logData); } } //4.4 Set<Entry<String,LogData>> entrySet = logoutMap.entrySet(); for(Entry<String,LogData> e : entrySet){ LogData logout = e.getValue(); LogData login = loginMap.remove(e.getKey()); LogRec logRec = new LogRec(login,logout); matches.add(logRec); } //5 IOUtil.saveCollection(matches, logRecFile); //6 IOUtil.saveCollection( loginMap.values(),loginLogFile ); //7 textLogFile.delete(); //8 return true; } catch (Exception e) { System.out.println("配對(duì)日志失敗!"); e.printStackTrace(); } return false; } /** * 第一步:解析日志 * @return true:解析成功 * false:解析失敗 */ private boolean parseLogs(){ /* * 實(shí)現(xiàn)思路: * 循環(huán)讀取batch條日志,然后將每條日志中的 * 5個(gè)信息解析出來(lái),最終組成一個(gè)字符串,以 * 行為單位,寫(xiě)入到textLogFile文件中 * * 實(shí)現(xiàn)步驟: * 1:必要的判斷工作 * 1.1:為了避免解析的日志還沒(méi)有被使用,而 * 第一步又重復(fù)執(zhí)行導(dǎo)致之前日志被覆蓋 * 的問(wèn)題,這里需要判斷,若保存解析后 * 的日志文件存在,則第一步不再執(zhí)行。 * 該日志文件會(huì)在第二步配對(duì)完畢后刪除。 * 1.2:logFile文件必須存在(wtmpx文件) * 1.3:是否還有日志可以解析 * 2:創(chuàng)建RandomAccessFile來(lái)讀取logFile * 3:將指針移動(dòng)到上次最后讀取的位置,準(zhǔn)備 * 開(kāi)始新的解析工作 * 4:解析工作 * 4.1:創(chuàng)建一個(gè)List集合,用于保存解析后 * 的每一條日志(LogData實(shí)例) * 4.2:循環(huán)batch次,解析每條日志中的 * 5項(xiàng)內(nèi)容(user,pid,type,time,host) * 并用一個(gè)LogData實(shí)例保存,然后將 * 該LogData實(shí)例存入集合 * 5:將集合中的所有的日志以行為單位保存到 * textLogFile中 * 6:保存書(shū)簽信息 * 7:返回true,表示工作完畢 * */ RandomAccessFile raf = null; try { //1 //1.1 if(textLogFile.exists()){ return true; } //1.2 if(!logFile.exists()){ System.out.println(logFile+"不存在!"); return false; } //1.3 long lastPosition = hasLogs(); //打樁 // System.out.println( // "lastPosition:"+lastPosition // ); if(lastPosition<0){ System.out.println("沒(méi)有日志可以解析了!"); return false; } //2 raf = new RandomAccessFile(logFile,"r"); //3 raf.seek(lastPosition); //4 List<LogData> list = new ArrayList<LogData>(); for(int i=0;i<batch;i++){ //每次解析前都判斷是否還有日志可以解析 if(logFile.length()-lastPosition <LogData.LOG_LENGTH ){ break; } //解析user raf.seek(lastPosition+LogData.USER_OFFSET); String user = IOUtil.readString( raf, LogData.USER_LENGTH ).trim(); //解析PID raf.seek(lastPosition+LogData.PID_OFFSET); int pid = raf.readInt(); //解析TYPE raf.seek(lastPosition+LogData.TYPE_OFFSET); short type = raf.readShort(); //解析TIME raf.seek(lastPosition+LogData.TIME_OFFSET); int time = raf.readInt(); //解析HOST raf.seek(lastPosition+LogData.HOST_OFFSET); String host = IOUtil.readString( raf, LogData.HOST_LENGTH ).trim(); LogData log = new LogData(user, pid, type, time, host); list.add(log); //打樁 // System.out.println(log); //當(dāng)解析完一條日志后,更新lastPosition lastPosition = raf.getFilePointer(); } //5 IOUtil.saveCollection(list, textLogFile); //6 保存書(shū)簽文件 IOUtil.saveLong( lastPosition, lastPositionFile); //7 return true; } catch (Exception e) { System.out.println("解析日志失敗!"); e.printStackTrace(); } finally{ if(raf != null){ try { raf.close(); } catch (IOException e) { e.printStackTrace(); } } } return false; } /** * 第一步解析日志中的一個(gè)環(huán)節(jié), * 根據(jù)書(shū)簽文件記錄的位置判斷是否還有 * 日志可以解析,若有,則將上次最后的位置 * 返回,若沒(méi)有則返回-1。 * @return */ private long hasLogs(){ try { /* * 若lastPositionFile不存在,則說(shuō)明 * 從來(lái)沒(méi)有解析過(guò),那么從頭開(kāi)始解析即可 */ if (!lastPositionFile.exists()){ return 0 ; } long lastPosition = IOUtil.readLong(lastPositionFile); if (logFile.length()-lastPosition >=LogData.LOG_LENGTH){ return lastPosition; } } catch (Exception e) { e.printStackTrace(); } return - 1 ; } public static void main(String[] args) { try { DMSClient client = new DMSClient(); client.start(); } catch (Exception e) { System.out.println( "客戶端運(yùn)行失敗!" ); } } } |
3. IOUtil.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
|
package com.dms; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.Collection; import java.util.List; import com.dms.bo.LogData; /** * 該類(lèi)是一個(gè)工具類(lèi),負(fù)責(zé)客戶端的IO操作 * @author Administrator * */ public class IOUtil { /** * 從給定的文件中讀取每一行字符串(配對(duì)日志) * 并存入一個(gè)集合后返回 * @param file * @return * @throws Exception */ public static List<String> loadLogRec(File file) throws Exception{ BufferedReader br = null ; try { br = new BufferedReader( new InputStreamReader( new FileInputStream( file ) ) ); List<String> list = new ArrayList<String>(); String line = null ; while ((line = br.readLine())!= null ){ list.add(line); } return list; } catch (Exception e) { e.printStackTrace(); throw e; } finally { if (br != null ){ br.close(); } } } /** * 從給定的文件中讀取每一條配對(duì)日志,并存入 * 一個(gè)集合中然后返回。 * @param file * @return * @throws Exception */ public static List<LogData> loadLogData(File file) throws Exception{ BufferedReader br = null ; try { br = new BufferedReader( new InputStreamReader( new FileInputStream( file ) ) ); List<LogData> list = new ArrayList<LogData>(); String line = null ; while ((line = br.readLine())!= null ){ LogData logData = new LogData(line); list.add(logData); } return list; } catch (Exception e) { e.printStackTrace(); throw e; } finally { if (br!= null ){ br.close(); } } } /** * 將指定的long值以字符串的形式寫(xiě)入到 * 給定文件的第一行 * @param l * @param file * @throws Exception */ public static void saveLong( long lon,File file) throws Exception{ PrintWriter pw = null ; try { pw = new PrintWriter(file); pw.println(lon); } catch (Exception e) { e.printStackTrace(); throw e; } finally { if (pw != null ){ pw.close(); } } } /** * 將集合中每個(gè)元素的toString方法返回的字符串 * 以行為單位寫(xiě)入到指定文件中。 * @param c * @param file * @throws Exception */ public static void saveCollection( Collection c,File file) throws Exception{ PrintWriter pw = null ; try { pw = new PrintWriter(file); for (Object o : c){ pw.println(o); } } catch (Exception e) { e.printStackTrace(); throw e; } finally { if (pw != null ){ pw.close(); } } } /** * 從給定的RandomAccessFile當(dāng)前位置開(kāi)始連續(xù) * 讀取length個(gè)字節(jié),并轉(zhuǎn)換為字符串后返回 * @param raf * @param length * @return * @throws Exception */ public static String readString( RandomAccessFile raf, int length) throws Exception{ try { byte [] data = new byte [length]; raf.read(data); return new String(data, "ISO8859-1" ); } catch (Exception e) { e.printStackTrace(); throw e; } } /** * 從給定文件中讀取第一行字符串,然后將其 * 轉(zhuǎn)換為一個(gè)long值后返回 * @param file * @return * @throws Exception */ public static long readLong(File file) throws Exception{ BufferedReader br = null ; try { br = new BufferedReader( new InputStreamReader( new FileInputStream( file ) ) ); String line = br.readLine(); return Long.parseLong(line); } catch (Exception e) { e.printStackTrace(); throw e; } finally { if (br != null ){ br.close(); } } } } |
4. config.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
<? xml version = "1.0" encoding = "UTF-8" ?> < config > <!-- unix系統(tǒng)日志文件名 --> < logfile >wtmpx</ logfile > <!-- 保存解析后日志的文件名 --> < textlogfile >log.txt</ textlogfile > <!-- 書(shū)簽文件名 --> < lastpositionfile >last-position.txt</ lastpositionfile > <!-- 每次解析日志的條目數(shù) --> < batch >10</ batch > <!-- 配對(duì)日志文件名 --> < logrecfile >logrec.txt</ logrecfile > <!-- 未配對(duì)日志文件名 --> < loginlogfile >login.txt</ loginlogfile > <!-- 服務(wù)端地址 --> < serverhost >localhost</ serverhost > <!-- 服務(wù)端端口 --> < serverport >8088</ serverport > </ config > |
5. server-config.xml
1
2
3
4
5
6
7
8
9
|
<? xml version = "1.0" encoding = "UTF-8" ?> < config > <!-- 服務(wù)端保存配對(duì)日志文件的文件名 --> < logrecfile >server-logs.txt</ logrecfile > <!-- 線程池線程數(shù)量 --> < threadsum >30</ threadsum > <!-- 服務(wù)端端口 --> < serverport >8088</ serverport > </ config > |
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。