需求
1)使用netty搭建一个服务端程序和一个客户端程序
2)客户端把上一个Demo的错误日志(就是你想要上传的文件)上传到服务端程序,如果想了解我上一个Demo点击这里
3)拓展功能,实现定时上传错误日志及可以使用telnet连接服务器手动控制上传错误日志
4)使用多线程拓展netty服务端,netty只负责收发消息,逻辑提交到其它线程处理
5)使用java反射技术改造程序,比如telnet用upload就调用upload方法上传数据,
调用display就调用display方法显示服务端上一次接收到的数据
先看Netty服务端和客户端的基本执行过程
1)初始化
2)初始化的时候new一个handler
3)在handler中执行方法
4)互相连接时触发channelActive,channelRead负责监听消息
代码效果
服务端
客户端
telnet中
打开控制台,输入telnet localhost 8888或者下图所示
连接后即可在窗口中输入不同指令来执行操作(暂时只对upload指令)
源代码链接导入IDE即可直接使用:点击这里
代码思路:服务端
1、启动FileUploadServer
1)创建一个线程开启telnet服务端,用于接收telnet发送的指令
Thread telnetTread = new Thread(new TelnetServer());
2、调用TelnetServer
1)TelnetServer的run()方法保存接收到的telnetClient指令
if(tmp != null && "upload".equalsIgnoreCase(tmp.trim())){
FileUploadServer.command = tmp;
out.println("ok!uploading...");
} else if(tmp != null && "display".equalsIgnoreCase(tmp.trim())) {
FileUploadServer.command = tmp;
if(FileUploadServer.uploadData.getNewFileName() == null) {
out.println("no file uploaded!");
} else {
out.println("last uploaded file: " + FileUploadServer.uploadData.getNewFileName());
}
} else {
out.println("invalidate instruction!");
}
2)FileUploadServerHandler类的channelRead(ChannelHandlerContext ctx, Object msg)方法监听指令,根据指令值执行不同操作(此处只对"upload"指令进行操作)
if("upload".equals(methodName.toLowerCase())){
comfirmUpload = true;
//FileUploadServer.command = null;
}
3)FileUploadServerHandler调用BusinessThreadUtil类使用java的反射机制执行当指令为"upload"时候的操作
if(comfirmUpload) {
//handler中,使用异步的线程池处理业务。防止handler卡住,导致netty并发性能不佳
Class<?> clazz = Class.forName("com.hx.util.BusinessThreadUtil");
Method method = clazz.getMethod("upload",Object.class, String.class);
method.invoke(null,msg, fileDir);
}
4)BusinessThreadUtil类调用UploadServerThread的run()方法保存上传的文件到服务端本地
//private RandomAccessFile raf;
raf = new RandomAccessFile(file, "rw");
raf.seek(0);
//保存
raf.write(bytes, 0, bytes.length);
代码思路:客户端
1、启动FileUploadClient
2、与服务端连接成功,触发FileUploadServerHandler的channelActive(ChannelHandlerContext ctx)方法
此时执行FileUploadClientHandler类的channelActive(ChannelHandlerContext ctx)方法,调用UploadClientTimerTask类的timerTask()方法开始定时上传文件的任务
UploadClientTimerTask uctt = new UploadClientTimerTask();
uctt.timerTask(path,errorLogPath,ctx);
1)UploadClientTimerTask类的timerTask()方法调用LogFilterUtil类,过滤日志文件,得到的异常信息是一段String
LogFilterUtil.logFilter(path,errorLogPath);
2)UploadClientTimerTask类的timerTask()方法调用bean实体类UploadData,保存过滤的内容,并向客户端发送要上传的对象
//private RandomAccessFile raf;
// r:只读
randomAccessFile = new RandomAccessFile(file, "r");
randomAccessFile.seek(0);//从开始位置开始读
long length = randomAccessFile.length();
//创建一个大小为文件长度的字节数组
byte[] bytes = new byte[(int) length];
//将文件读入字节数组,一次读完
randomAccessFile.read(bytes);
uploadData.setData(bytes);
uploadData.setOrignFileName(file.getName());
//向客户端发送要上传的对象
ctx.writeAndFlush(uploadData);
3)UploadClientTimerTask类的timerTask()方法调用addTask(this);方法自身递归,根据每个solt执行定时任务
//根据时长把task任务放到响应的solt上
timer.newTimeout(task, 100, TimeUnit.MILLISECONDS);
ps:我只是搬运工,代码所有权一位兄dei