服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服务器之家 - 编程语言 - JAVA教程 - java读取用户登入退出日志信息上传服务端

java读取用户登入退出日志信息上传服务端

2020-04-29 12:08外卖担当 JAVA教程

这篇文章主要介绍了java读取用户登入退出日志信息上传服务端的相关资料,需要的朋友可以参考下

本文实例为大家分享了读取用户登入出日志上传服务端的具体实现代码,供大家参考,具体内容如下

该客户端运行在给用户提供unix服务的服务器上。用来读取并收集该服务器上用户的上下线信息,并进行配对整理后发送给服务端汇总。

具体实现代码:

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服务端,用来接收每个客户端发送过来的
 * 配对日志并保存在本地文件中
 * @author Administrator
 *
 */
public class DMSServer {
  //属性定义
  //用来接收客户端连接的服务端的ServerSocket
  private ServerSocket server;
  //用来管理处理客户端请求的线程的线程池
  private ExecutorService threadPool;
  //保存所有客户端发送过来配对日志的文件
  private File serverLogFile;
  //消息队列
  private BlockingQueue<String> messageQueue = new LinkedBlockingQueue<String>();
   
  public DMSServer() throws Exception{
    try {
      System.out.println("服务端正在初始化...");
      //1 解析配置文件server-config.xml
      Map<String,String> config = loadConfig();
       
      //2 根据配置文件内容初始化属性
      init(config);
      System.out.println("服务端初始化完毕...");
    } catch (Exception e) {
      System.out.println("初始化服务端失败!");
      throw e;
    }
  }
   
  /**
   * 构造方法初始化第一步,解析配置文件
   * @return 返回的Map中保存的是配置文件中的
   *     每一条内容,其中key:标签的名字,
   *     value为标签中间的文本
   * @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>标签中的所有子标签
       * 并将每一个子标签的名字作为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;
    }
  }
   
  /**
   * 构造方法初始化第二步,根据配置项初始化属性
   * @param config
   * @throws Exception
   */
  private void init(Map<String,String> config) throws Exception{
    /*
     * 用配置文件中的<logrecfile>初始化属性:serverLogFile
     * 用配置文件中的<threadsum>初始化属性:threadPool,这里创建固定大小线程池。该值作为线程池线程数量
     * 用配置文件中的<serverport>初始化属性:server,这里这个值为ServerSocket的服务端口
     */
    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")) 
    );
  
  /**
   * 服务端开始工作的方法
   * @throws Exception
   */
  public void start() throws Exception{
    /*
     * 实现要求:
     * 首先单独启动一个线程,用来运行SaveLogHandler
     * 这个任务,目的是保存所有配对日志
     * 然后开始循环监听服务端端口,一旦一个客户端连接了,
     * 就实例化一个ClientHander,然后将该任务交给线程池
     * 使其分配线程来处理与该客户端的交互。
     *
     */
    try {
      System.out.println("服务端开始工作...");
      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("启动服务端失败!");
    }
  }
  /**
   * 该线程负责从消息队列中取出每一条配对日志,
   * 并存入到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();
        }
      }
    }
  }
   
  /**
   * 处理一个指定客户端请求
   * @author Administrator
   *
   */
  private class ClientHandler implements Runnable{
    private Socket socket;
    public ClientHandler(Socket socket){
      this.socket = socket;
    }
    public void run(){
      /*
       * 思路:
       * 首先接收客户端发送过来的所有配对日志,
       * 直到读取到"OVER"为止,然后将这些配对
       * 日志保存到本地的文件中,并回复客户端
       * "OK"
       * 执行步骤:
       * 1:通过Socket创建输出流,用来给客户端
       *  发送响应
       * 2:通过Socket创建输入流,读取客户端发送
       *  过来的日志
       * 3:循环读取客户端发送过来的每一行字符串,并
       *  先判断是否为字符串"OVER",若不是,则是
       *  一条配对日志,那么保存到本地文件,若是,
       *  则停止读取。
       * 4:成功读取所有日志后回复客户端"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;
          }
          //将该日志写入文件保存
          messageQueue.offer(message);
        }
         
        //4
        pw.println("OK");
        pw.flush();
         
         
      } catch (Exception e) {
        e.printStackTrace();
        pw.println("ERROR");
        pw.flush();
      } finally{
        try {
          //与客户端断开连接释放资源
          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;
 
/**
 * 该客户端运行在给用户提供unix服务的服务器上。
 * 用来读取并收集该服务器上用户的上下线信息,并
 * 进行配对整理后发送给服务端汇总。
 * @author Administrator
 *
 */
public class DMSClient {
  //属性定义
   
  //第一步:解析日志所需属性
  //unix系统日志文件
  private File logFile;
  //保存解析后日志的文件
  private File textLogFile;
  //书签文件
  private File lastPositionFile;
  //每次解析日志的条目数
  private int batch;
   
  //第二步:配对日志所需要属性
  //保存配对日志的文件
  private File logRecFile;
  //保存未配对日志的文件
  private File loginLogFile;
   
  //第三步:发送日志所需要属性
  //服务端地址
  private String serverHost;
  //服务端端口
  private int serverPort;
   
  /**
   * 构造方法,用来初始化客户端
   * @throws Exception
   */
  public DMSClient() throws Exception{
    try {
      //1 解析配置文件config.xml
      Map<String,String> config = loadConfig();
      //打桩
      System.out.println(config);
       
      //2 根据配置文件内容初始化属性
      init(config);
       
    } catch (Exception e) {
      System.out.println("初始化失败!");
      throw e;
    }
  }
  /**
   * 构造方法初始化第二步,根据配置项初始化属性
   * @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;
    }
  }
   
   
  /**
   * 构造方法初始化第一步,解析配置文件
   * @return 返回的Map中保存的是配置文件中的
   *     每一条内容,其中key:标签的名字,
   *     value为标签中间的文本
   * @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>标签中的所有子标签
       * 并将每一个子标签的名字作为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;
    }
  }
   
  /**
   * 客户端开始工作的方法
   * 循环执行三步:
   * 1:解析日志
   * 2:配对日志
   * 3:发送日志
   */
  public void start(){
    parseLogs();
    matchLogs();
    sendLogs();
//   while(true){
//     //解析日志
//     if(!parseLogs()){
//       continue;
//     }
//     //配对日志
//     if(!matchLogs()){
//       continue;
//     }
//     //发送日志
//     sendLogs();
//   }
  }
  /**
   * 第三步:发送日志
   * @return true:发送成功
   *     false:发送失败
   */
  private boolean sendLogs(){
      /*
       * 实现思路:
       * 将logRecFile文件中的所有配对日志读取
       * 出来然后连接上服务端并发送过去,若服务端
       * 全部接收,就可以将该文件删除,表示发送
       * 完毕了。
       * 实现步骤:
       * 1:logRecFile文件必须存在
       * 2:将所有配对日志读取出来并存入一个集合
       *  等待发送
       * 3:通过Socket连接服务端
       * 4:创建输出流
       * 5:顺序将所有配对日志按行发送给服务端
       * 6:单独发送一个字符串"OVER"表示所有日志
       *  均已发送完毕
       * 7:创建输入流
       * 8:读取服务端发送回来的响应字符串
       * 9:若响应的字符串为"OK",表示服务端正常
       *  接收了所有日志,这时就可以将logRecFile
       *  文件删除并返回true表示发送完毕。
       *   
       */
    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("发送日志失败!");
        return false;
      }
       
    } catch (Exception e) {
      System.out.println("发送日志失败!");
      e.printStackTrace();
    } finally{
      if(socket != null){
        try {
          socket.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    return false;
  }
   
  /**
   * 第二步:配对日志
   * @return true:配对成功
   *     false:配对失败
   */
  private boolean matchLogs(){
     
      /*
       * 实现思路:
       * 将第一步解析的新日志,与上次为配对成功
       * 的登入日志全部读取出来,然后再按照user,
       * pid相同,type一个是7,一个是8进行配对。
       * 只要能找到类型为8的,一定可以找到一个
       * 能与之配对的登入日志。
       *
       * 实现步骤:
       * 1:必要的判断
       *  1.1:logRecFile是否存在,存在则不再
       *    进行新的配对工作,避免覆盖。
       *  1.2:textLogFile文件必须存在。 
       * 2:读取textLogFile将日志读取出来,并
       *  存入到集合中。(若干LogData实例)
       * 3:若loginLogFile文件若存在,则说明
       *  有上次未配对成功的日志,也将其读取
       *  出来存入集合等待一起配对
       * 4:配对工作
       *  4.1:创建一个集合,用于保存所有配对日志
       *  4.2:创建两个Map分别保存登入日志与登出日志
       *  4.3:遍历所有待配对的日志,按照登入与登出
       *    分别存入两个Map中,
       *    其中key:user,pid
       *      value:LogData实例
       *  4.4:遍历登出Map,并根据每条登出日志的key
       *    去登入Map中找到对应的登入日志,并
       *    以一个LogRec实例保存该配对日志,然后
       *    存入配对日志的集合中。并将该配对日志
       *    中的登入日志从登入Map中删除。这样一来
       *    登入Map中应当只剩下没有配对的了。
       * 5:将配对日志写入到logRecFile中
       * 6:将所有未配对日志写入到loginLogFile中
       * 7:将textLogFile文件删除
       * 8:返回true,表示配对完毕
       *
       */
    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("配对日志失败!");
      e.printStackTrace();
    }
    return false;
  }
   
  /**
   * 第一步:解析日志
   * @return true:解析成功
   *     false:解析失败
   */
  private boolean parseLogs(){
    /*
     * 实现思路:
     * 循环读取batch条日志,然后将每条日志中的
     * 5个信息解析出来,最终组成一个字符串,以
     * 行为单位,写入到textLogFile文件中
     *
     * 实现步骤:
     * 1:必要的判断工作
     *  1.1:为了避免解析的日志还没有被使用,而
     *    第一步又重复执行导致之前日志被覆盖
     *    的问题,这里需要判断,若保存解析后
     *    的日志文件存在,则第一步不再执行。
     *    该日志文件会在第二步配对完毕后删除。
     *  1.2:logFile文件必须存在(wtmpx文件)
     *  1.3:是否还有日志可以解析
     * 2:创建RandomAccessFile来读取logFile
     * 3:将指针移动到上次最后读取的位置,准备
     *  开始新的解析工作
     * 4:解析工作
     *  4.1:创建一个List集合,用于保存解析后
     *    的每一条日志(LogData实例)
     *  4.2:循环batch次,解析每条日志中的
     *    5项内容(user,pid,type,time,host)
     *    并用一个LogData实例保存,然后将
     *    该LogData实例存入集合
     * 5:将集合中的所有的日志以行为单位保存到
     *  textLogFile中
     * 6:保存书签信息    
     * 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("没有日志可以解析了!");
        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);
         
        //当解析完一条日志后,更新lastPosition
        lastPosition = raf.getFilePointer();
      }
       
      //5
      IOUtil.saveCollection(list, textLogFile);
       
      //6 保存书签文件
      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;
  }
  /**
   * 第一步解析日志中的一个环节,
   * 根据书签文件记录的位置判断是否还有
   * 日志可以解析,若有,则将上次最后的位置
   * 返回,若没有则返回-1。
   * @return
   */
  private long hasLogs(){
    try {
      /*
       * 若lastPositionFile不存在,则说明
       * 从来没有解析过,那么从头开始解析即可
       */
      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("客户端运行失败!");
    }
  }
}

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;
 
/**
 * 该类是一个工具类,负责客户端的IO操作
 * @author Administrator
 *
 */
public class IOUtil {
  /**
   * 从给定的文件中读取每一行字符串(配对日志)
   * 并存入一个集合后返回
   * @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();
      }
    }
  }
  /**
   * 从给定的文件中读取每一条配对日志,并存入
   * 一个集合中然后返回。
   * @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值以字符串的形式写入到
   * 给定文件的第一行
   * @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();
      }
    }
  }
   
  /**
   * 将集合中每个元素的toString方法返回的字符串
   * 以行为单位写入到指定文件中。
   * @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当前位置开始连续
   * 读取length个字节,并转换为字符串后返回
   * @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;
    }
  }
   
  /**
   * 从给定文件中读取第一行字符串,然后将其
   * 转换为一个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系统日志文件名 -->
  <logfile>wtmpx</logfile>
  <!-- 保存解析后日志的文件名 -->
  <textlogfile>log.txt</textlogfile>
  <!-- 书签文件名 -->
  <lastpositionfile>last-position.txt</lastpositionfile>
  <!-- 每次解析日志的条目数 -->
  <batch>10</batch>
  <!-- 配对日志文件名 -->
  <logrecfile>logrec.txt</logrecfile>
  <!-- 未配对日志文件名 -->
  <loginlogfile>login.txt</loginlogfile>
  <!-- 服务端地址 -->
  <serverhost>localhost</serverhost>
  <!-- 服务端端口 -->
  <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>
  <!-- 服务端保存配对日志文件的文件名 -->
  <logrecfile>server-logs.txt</logrecfile>
  <!-- 线程池线程数量 -->
  <threadsum>30</threadsum>
  <!-- 服务端端口 -->
  <serverport>8088</serverport>
</config>

以上就是本文的全部内容,希望对大家的学习有所帮助。

延伸 · 阅读

精彩推荐