├── img ├── 001.jpg └── 002.jpg ├── netty-client ├── doc │ └── img │ │ └── 001.jpg ├── src │ └── main │ │ └── java │ │ └── com │ │ └── lwhtarena │ │ └── netty │ │ ├── tutorial05 │ │ ├── module │ │ │ ├── enums │ │ │ │ ├── QueryType.java │ │ │ │ └── MsgType.java │ │ │ ├── PingMsg.java │ │ │ ├── LoginMsg.java │ │ │ ├── CometMsg.java │ │ │ ├── BaseMsg.java │ │ │ └── QueryMsg.java │ │ └── readme.md │ │ ├── heartbeat │ │ ├── API.java │ │ ├── ClientHandler.java │ │ ├── MessageDecoder.java │ │ ├── MessageEncoder.java │ │ ├── AcceptorIdleStateTrigger.java │ │ └── asdsad.java │ │ ├── tutorial02 │ │ ├── thread02 │ │ │ ├── readme.md │ │ │ ├── DemoThread.java │ │ │ ├── ContinueThread.java │ │ │ ├── TestThread.java │ │ │ ├── ControllerThread.java │ │ │ ├── TestThread2.java │ │ │ └── ReadThread.java │ │ ├── thread01 │ │ │ ├── Control.java │ │ │ ├── TestThread.java │ │ │ └── Thread1.java │ │ └── httpClient │ │ │ └── ClientAbortMethod.java │ │ ├── tutorial04 │ │ ├── proto │ │ │ └── Packet.proto │ │ └── ClientHeartbeatHandler.java │ │ ├── tutorial03 │ │ ├── model │ │ │ ├── Event.java │ │ │ ├── RecvieMessage.java │ │ │ ├── SecureModel.java │ │ │ ├── Process.java │ │ │ ├── ResponseFile.java │ │ │ └── RequestFile.java │ │ ├── client │ │ │ ├── NettyMessageEncoder.java │ │ │ └── NettyMessageDecoder.java │ │ ├── test │ │ │ └── LargeMappedFiles.java │ │ └── util │ │ │ └── ObjectConvertUtil.java │ │ ├── tutorial06 │ │ ├── DownFileUtility.java │ │ ├── TestMethod.java │ │ ├── DownFileAccess.java │ │ └── DownFileInfoBean.java │ │ ├── demo02 │ │ ├── User.java │ │ ├── ObjectClientHandler.java │ │ └── ObjectClient.java │ │ ├── tutorial01 │ │ ├── HelloClientHandler.java │ │ ├── HelloClientInitializer.java │ │ └── HelloClient.java │ │ └── demo01 │ │ └── HttpClientInboundHandler.java ├── netty-client.iml └── pom.xml ├── nettyy-demo01 ├── src │ └── main │ │ ├── webapp │ │ ├── index.jsp │ │ └── WEB-INF │ │ │ └── web.xml │ │ └── java │ │ └── com │ │ └── lwhtarena │ │ ├── netty │ │ ├── netty4 │ │ │ ├── model │ │ │ │ ├── Event.java │ │ │ │ ├── RecvieMessage.java │ │ │ │ ├── SecureModel.java │ │ │ │ ├── ResponseFile.java │ │ │ │ └── RequestFile.java │ │ │ ├── client │ │ │ │ ├── NettyMessageEncoder.java │ │ │ │ └── NettyMessageDecoder.java │ │ │ └── util │ │ │ │ └── ObjectConvertUtil.java │ │ ├── netty │ │ │ └── readme.md │ │ └── 基本案例01 │ │ │ └── echo │ │ │ ├── server │ │ │ └── EchoServerHandler.java │ │ │ └── client │ │ │ └── EchoClientHandler.java │ │ └── xuchuan │ │ ├── Utility.java │ │ ├── TestMethod.java │ │ ├── FileAccess.java │ │ ├── readme.md │ │ └── SiteInfoBean.java ├── pom.xml └── nettyy-demo01.iml ├── .idea ├── copyright │ └── profiles_settings.xml ├── vcs.xml ├── artifacts │ ├── nettyy_demo01_war.xml │ └── nettyy_demo01_war_exploded.xml ├── libraries │ ├── Maven__junit_junit_3_8_1.xml │ ├── Maven__log4j_log4j_1_2_17.xml │ ├── Maven__org_slf4j_slf4j_api_1_6_6.xml │ ├── Maven__com_alibaba_fastjson_1_2_2.xml │ ├── Maven__org_slf4j_slf4j_log4j12_1_6_6.xml │ ├── Maven__io_netty_netty_all_4_1_6_Final.xml │ ├── Maven__org_jboss_netty_netty_3_2_1_Final.xml │ ├── Maven__io_netty_netty_all_4_0_23_Final.xml │ ├── Maven__io_netty_netty_codec_4_1_4_Final.xml │ ├── Maven__commons_logging_commons_logging_1_2.xml │ ├── Maven__io_netty_netty_buffer_4_1_4_Final.xml │ ├── Maven__io_netty_netty_common_4_1_4_Final.xml │ ├── Maven__io_netty_netty_handler_4_1_4_Final.xml │ ├── Maven__commons_logging_commons_logging_1_1_1.xml │ ├── Maven__com_google_protobuf_protobuf_java_3_1_0.xml │ ├── Maven__io_netty_netty_resolver_4_1_4_Final.xml │ ├── Maven__io_netty_netty_transport_4_1_4_Final.xml │ ├── Maven__org_mortbay_jetty_servlet_api_2_5_6_1_14.xml │ ├── Maven__io_netty_netty_codec_http_4_1_4_Final.xml │ ├── Maven__org_springframework_spring_core_3_2_3_RELEASE.xml │ └── Maven__org_springframework_spring_core_4_2_7_RELEASE.xml ├── encodings.xml ├── misc.xml ├── modules.xml └── compiler.xml ├── netty-server ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── lwhtarena │ │ │ └── netty │ │ │ ├── netty4 │ │ │ └── downServer │ │ │ │ ├── readme.md │ │ │ │ ├── HttpChannelInitlalizer.java │ │ │ │ └── HttpFileListenServerBootstarp.java │ │ │ ├── heartbeat │ │ │ ├── API.java │ │ │ ├── UserHandler.java │ │ │ ├── MessageEncoder.java │ │ │ ├── AcceptorIdleStateTrigger.java │ │ │ └── MessageDecoder.java │ │ │ ├── demo01 │ │ │ ├── readme.md │ │ │ └── HttpServer.java │ │ │ ├── tutorial04 │ │ │ ├── proto │ │ │ │ └── Packet.proto │ │ │ └── Server.java │ │ │ ├── tutorial03 │ │ │ ├── model │ │ │ │ ├── Event.java │ │ │ │ ├── RecvieMessage.java │ │ │ │ ├── SecureModel.java │ │ │ │ └── RequestFile.java │ │ │ ├── code │ │ │ │ ├── NettyMessageEncoder.java │ │ │ │ └── NettyMessageDecoder.java │ │ │ ├── server │ │ │ │ ├── FileChannelInitializer.java │ │ │ │ └── SecureServerHandler.java │ │ │ ├── readme.md │ │ │ └── util │ │ │ │ ├── FileTransferProperties.java │ │ │ │ └── ObjectConvertUtil.java │ │ │ ├── demo02 │ │ │ ├── User.java │ │ │ ├── ObjectServerHandler.java │ │ │ └── ObjectServer.java │ │ │ ├── tutorial02 │ │ │ ├── RandomAccessFileDemo01.java │ │ │ ├── MapMemeryBuffer01.java │ │ │ ├── MapMemeryBuffer02.java │ │ │ ├── LargeMappedFiles.java │ │ │ └── TestRandomAccessFile.java │ │ │ ├── tutorial01 │ │ │ ├── HelloServerInitializer.java │ │ │ ├── HelloServerHandler.java │ │ │ └── HelloServer.java │ │ │ └── readme.md │ │ └── resources │ │ └── systemConfig.properties └── netty-server.iml ├── netty-file-client ├── src │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── lwhtarena │ │ │ └── netty │ │ │ ├── QueueTask.java │ │ │ ├── TestA.java │ │ │ ├── PushTask.java │ │ │ └── ThreadPool.java │ └── main │ │ └── java │ │ └── com │ │ └── lwhtarena │ │ └── netty │ │ └── netty4 │ │ ├── model │ │ ├── Event.java │ │ ├── RecvieMessage.java │ │ ├── SecureModel.java │ │ ├── Process.java │ │ ├── ResponseFile.java │ │ └── RequestFile.java │ │ ├── client │ │ ├── NettyMessageEncoder.java │ │ └── NettyMessageDecoder.java │ │ └── util │ │ └── ObjectConvertUtil.java ├── netty-file-client.iml └── pom.xml ├── netty-file-server ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── lwhtarena │ │ │ │ └── netty │ │ │ │ └── netty4 │ │ │ │ ├── model │ │ │ │ ├── Event.java │ │ │ │ ├── RecvieMessage.java │ │ │ │ ├── SecureModel.java │ │ │ │ └── RequestFile.java │ │ │ │ ├── code │ │ │ │ ├── NettyMessageEncoder.java │ │ │ │ └── NettyMessageDecoder.java │ │ │ │ ├── server │ │ │ │ ├── FileChannelInitializer.java │ │ │ │ ├── SecureServerHandler.java │ │ │ │ └── FileTransferServer.java │ │ │ │ └── util │ │ │ │ ├── FileTransferProperties.java │ │ │ │ └── ObjectConvertUtil.java │ │ └── resources │ │ │ └── systemConfig.properties │ └── test │ │ └── java │ │ └── com │ │ └── lwhtarena │ │ └── netty │ │ └── AppTest.java ├── netty-file-server.iml └── pom.xml └── netty-bigFile ├── src └── main │ └── java │ └── com │ └── lwhtarena │ └── netty │ ├── bigFile │ ├── client │ │ ├── TestMonitor.java │ │ └── MonitorThread.java │ ├── intermediary │ │ ├── IntermediaryChannelHandler.java │ │ ├── IntermediaryClient.java │ │ └── OptionHandler.java │ └── server │ │ ├── HttpChannelInitlalizer.java │ │ └── HttpFileListenServerBootstarp.java │ └── file │ ├── HttpStaticFileServer.java │ └── HttpStaticFileServerInitializer.java ├── pom.xml └── netty-bigFile.iml /img/001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LWHTarena/netty-file/HEAD/img/001.jpg -------------------------------------------------------------------------------- /img/002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LWHTarena/netty-file/HEAD/img/002.jpg -------------------------------------------------------------------------------- /netty-client/doc/img/001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LWHTarena/netty-file/HEAD/netty-client/doc/img/001.jpg -------------------------------------------------------------------------------- /nettyy-demo01/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | 2 |
测试线程!
工具类,放一些简单的方法
7 | */ 8 | public class TestMethod { 9 | public TestMethod() { ///xx/weblogic60b2_win.exe 10 | try { 11 | SiteInfoBean bean = new SiteInfoBean("http://localhost/xx/weblogic60b2_win.exe", 12 | "L:\\temp", "weblogic60b2_win.exe", 5); 13 | //SiteInfoBean bean = new SiteInfoBean("http://localhost:8080/down.zip","L:\\temp","weblogic60b2_win.exe", 5); 14 | SiteFileFetch fileFetch = new SiteFileFetch(bean); 15 | fileFetch.start(); 16 | } catch (Exception e) { 17 | e.printStackTrace(); 18 | } 19 | } 20 | 21 | public static void main(String[] args) { 22 | new TestMethod(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/heartbeat/MessageEncoder.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.heartbeat; 2 | 3 | import java.util.List; 4 | 5 | import io.netty.buffer.ByteBuf; 6 | import io.netty.buffer.Unpooled; 7 | import io.netty.handler.codec.MessageToMessageEncoder; 8 | 9 | 10 | /** 11 | * @ModifiedBy 修改人 12 | * @Project MessageEncoder 13 | * @Desciption 编码器 14 | * 15 | * @Author SuFH 16 | * @Data 2016-5-18下午2:26:25 17 | * 18 | */ 19 | public class MessageEncoder extends MessageToMessageEncoder { 20 | 21 | @Override 22 | protected void encode(io.netty.channel.ChannelHandlerContext arg0, 23 | String msg, List out) throws Exception { 24 | byte[] tmp = msg.getBytes(); 25 | ByteBuf b = Unpooled.buffer(); 26 | b.writeInt(tmp.length); 27 | b.writeBytes(tmp); 28 | out.add(b); 29 | System.out.println("MessageEncoder"+ "发送信息"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial06/DownFileUtility.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial06; 2 | 3 | /** 4 | * @author: liwh 5 | * @Date: 2017/2/6. 6 | * @Description:简单的工具类 7 | */ 8 | public class DownFileUtility { 9 | public DownFileUtility() { 10 | } 11 | 12 | /** 13 | * 休眠时长 14 | * @param nSecond 15 | */ 16 | public static void sleep(int nSecond) { 17 | try { 18 | Thread.sleep(nSecond); 19 | } catch (Exception e) { 20 | e.printStackTrace(); 21 | } 22 | } 23 | 24 | /** 25 | * 打印日志信息 26 | * @param sMsg 27 | */ 28 | public static void log(String sMsg) { 29 | System.err.println(sMsg); 30 | } 31 | 32 | /** 33 | * 打印日志信息 34 | * @param sMsg 35 | */ 36 | public static void log(int sMsg) { 37 | System.err.println(sMsg); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial02/thread01/Control.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial02.thread01; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * @author: liwh 7 | * @Date: 2017/2/5. 8 | * @Description: 9 | */ 10 | public class Control extends Thread { 11 | private Thread1 t; 12 | public Control(Thread1 t) { 13 | this.t = t; 14 | } 15 | 16 | public void run() { 17 | while(true) { 18 | int r=0; 19 | try { 20 | r=System.in.read(); 21 | } catch (IOException e) { 22 | e.printStackTrace(); 23 | } 24 | if(r == 'g') { 25 | t.setSleep(false); 26 | } else if(r == 'w') { 27 | t.setSleep(true); 28 | } else if(r == 's') { 29 | t.setStop(true); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/heartbeat/AcceptorIdleStateTrigger.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.heartbeat; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | import io.netty.handler.timeout.IdleState; 6 | import io.netty.handler.timeout.IdleStateEvent; 7 | 8 | 9 | public class AcceptorIdleStateTrigger extends ChannelInboundHandlerAdapter { 10 | 11 | @Override 12 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 13 | if (evt instanceof IdleStateEvent) { 14 | IdleState state = ((IdleStateEvent) evt).state(); 15 | if (state == IdleState.READER_IDLE) { 16 | throw new Exception("idle exception"); 17 | } 18 | } else { 19 | System.out.println("jiesd asd"); 20 | super.userEventTriggered(ctx, evt); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial02/thread02/ControllerThread.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial02.thread02; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * @author: liwh 7 | * @Date: 2017/2/5. 8 | * @Description: 9 | */ 10 | public class ControllerThread implements Runnable { 11 | 12 | private ReadThread rt; 13 | 14 | public ControllerThread(ReadThread rt) { 15 | this.rt = rt; 16 | } 17 | 18 | @Override 19 | public void run() { 20 | while (true){ 21 | 22 | int r =0; 23 | try { 24 | r =System.in.read(); 25 | } catch (IOException e) { 26 | e.printStackTrace(); 27 | } 28 | 29 | if(r=='g'){ //暂停 30 | rt.suspend(); 31 | }else if(r == 'w'){ //继续 32 | rt.resume(); 33 | } 34 | } 35 | 36 | } 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/demo02/User.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.demo02; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author: liwh 7 | * @Date: 2017/1/12. 8 | * @Description:netty 传输序列化对象 9 | */ 10 | public class User implements Serializable { 11 | 12 | private Long id; 13 | private String username; 14 | 15 | public User() { 16 | } 17 | 18 | public Long getId() { 19 | return id; 20 | } 21 | 22 | public void setId(Long id) { 23 | this.id = id; 24 | } 25 | 26 | public String getUsername() { 27 | return username; 28 | } 29 | 30 | public void setUsername(String username) { 31 | this.username = username; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "User{" + 37 | "id=" + id + 38 | ", username='" + username + '\'' + 39 | '}'; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/demo02/User.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.demo02; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author: liwh 7 | * @Date: 2017/1/12. 8 | * @Description:netty 传输序列化对象 9 | */ 10 | public class User implements Serializable { 11 | 12 | private Long id; 13 | private String username; 14 | 15 | public User() { 16 | } 17 | 18 | public Long getId() { 19 | return id; 20 | } 21 | 22 | public void setId(Long id) { 23 | this.id = id; 24 | } 25 | 26 | public String getUsername() { 27 | return username; 28 | } 29 | 30 | public void setUsername(String username) { 31 | this.username = username; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "User{" + 37 | "id=" + id + 38 | ", username='" + username + '\'' + 39 | '}'; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /nettyy-demo01/src/main/java/com/lwhtarena/xuchuan/FileAccess.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.xuchuan; 2 | 3 | import java.io.IOException; 4 | import java.io.RandomAccessFile; 5 | 6 | /** 7 | * @author: liwh 8 | * @Date: 2017/2/6. 9 | * @Description:负责文件的存储 10 | */ 11 | public class FileAccess { 12 | RandomAccessFile oSavedFile; 13 | long nPos; 14 | 15 | public FileAccess() throws IOException { 16 | this("", 0); 17 | } 18 | 19 | public FileAccess(String sName, long nPos) throws IOException { 20 | oSavedFile = new RandomAccessFile(sName, "rw"); 21 | this.nPos = nPos; 22 | oSavedFile.seek(nPos); 23 | } 24 | 25 | public synchronized int write(byte[] b, int nStart, int nLen) { 26 | int n = -1; 27 | try { 28 | oSavedFile.write(b, nStart, nLen); 29 | n = nLen; 30 | } catch (IOException e) { 31 | e.printStackTrace(); 32 | } 33 | return n; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /netty-bigFile/src/main/java/com/lwhtarena/netty/bigFile/client/MonitorThread.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.bigFile.client; 2 | 3 | /** 4 | * @author: liwh 5 | * @Date: 2017/2/7. 6 | * @Description: 7 | */ 8 | public class MonitorThread implements Runnable{ 9 | 10 | public Thread t; 11 | 12 | private String threadName; 13 | 14 | boolean suspended =false; 15 | 16 | public MonitorThread(String threadName) { 17 | this.threadName = threadName; 18 | System.out.println("创建线程..."+threadName); 19 | } 20 | 21 | public void run() { 22 | 23 | } 24 | 25 | /**开始**/ 26 | public void start(){ 27 | if(t==null){ 28 | t =new Thread(this,threadName); 29 | t.start(); 30 | } 31 | } 32 | 33 | /** 34 | * 暂停 35 | */ 36 | public void suspend(){ 37 | suspended =true; 38 | } 39 | 40 | synchronized void resume(){ 41 | suspended =false; 42 | notify(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial01/HelloClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial01; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.SimpleChannelInboundHandler; 5 | 6 | /** 7 | * @author: liwh 8 | * @Date: 2017/1/13. 9 | * @Description: 10 | */ 11 | public class HelloClientHandler extends SimpleChannelInboundHandler { 12 | 13 | @Override 14 | protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { 15 | 16 | System.out.println("Server say : " + msg); 17 | } 18 | 19 | @Override 20 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 21 | System.out.println("Client active "); 22 | super.channelActive(ctx); 23 | } 24 | 25 | @Override 26 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 27 | System.out.println("Client close "); 28 | super.channelInactive(ctx); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/heartbeat/MessageDecoder.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.heartbeat; 2 | 3 | import java.nio.charset.Charset; 4 | import java.util.List; 5 | 6 | import io.netty.buffer.ByteBuf; 7 | import io.netty.buffer.Unpooled; 8 | import io.netty.handler.codec.MessageToMessageDecoder; 9 | 10 | public class MessageDecoder extends MessageToMessageDecoder { 11 | 12 | @Override 13 | protected void decode(io.netty.channel.ChannelHandlerContext arg0, 14 | ByteBuf buffer, List out) throws Exception { 15 | if (buffer.readableBytes() < 4) { 16 | return; 17 | } 18 | int dataLength = buffer.readInt(); 19 | buffer.markReaderIndex(); 20 | if(dataLength>buffer.readableBytes()) 21 | { 22 | return; 23 | } 24 | ByteBuf resultBuf = Unpooled.buffer(); 25 | resultBuf.writeBytes(buffer, buffer.readerIndex(), dataLength); 26 | //服务端解码 27 | out.add(resultBuf.toString(Charset.defaultCharset())); 28 | // out.add(buffer.toString(Charset.defaultCharset())); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial02/thread01/TestThread.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial02.thread01; 2 | 3 | /** 4 | * @author: liwh 5 | * @Date: 2017/2/5. 6 | * @Description: 7 | * 8 | 程序说明: 9 | 1,刚开始程序的等待的。 10 | 2,你输入‘g’回车后会运行。 11 | 3,你输入‘w’回车后会再次等待。 12 | 4,再次输入‘g’回车后又会运行。 13 | 5,输入‘s'回车,会终止程序。 14 | 6,这里将控制线程设置成了Deamon的形式,因为线程t由线程c控制可以终止,而线程c始终无法终止,所以把它设置 15 | 为后台线程,当让控制的线程t退出时,所有的前台线程都结束了,这样线程c就可以自动退出。 16 | * 17 | */ 18 | public class TestThread { 19 | public static void main(String[] args) { 20 | Thread1 t = new Thread1(); 21 | Thread c = new Control(t); 22 | t.setSleep(true); 23 | c.setDaemon(true); 24 | 25 | t.start(); 26 | c.start(); 27 | System.out.println("You can input 'g' and 'Enter' to start your job."); 28 | System.out.println("You can input 'w' and 'Enter' to let your job to wait..."); 29 | System.out.println("You can input 's' and 'Enter' to finish your job."); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/demo02/ObjectServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.demo02; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | 6 | /** 7 | * @author: liwh 8 | * @Date: 2017/1/12. 9 | * @Description: 10 | */ 11 | public class ObjectServerHandler extends ChannelInboundHandlerAdapter { 12 | @Override 13 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 14 | User user = (User) msg; 15 | System.out.println(user); 16 | user.setUsername("ooxx"); 17 | ctx.write(user); 18 | ctx.flush(); 19 | } 20 | 21 | @Override 22 | public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { 23 | ctx.close(); 24 | } 25 | 26 | @Override 27 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 28 | //打印异常信息并关闭连接 29 | cause.printStackTrace(); 30 | ctx.close(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /netty-bigFile/src/main/java/com/lwhtarena/netty/bigFile/intermediary/IntermediaryChannelHandler.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.bigFile.intermediary; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.socket.SocketChannel; 5 | import io.netty.handler.codec.http.HttpRequestEncoder; 6 | import io.netty.handler.codec.http.HttpResponseDecoder; 7 | import io.netty.handler.stream.ChunkedWriteHandler; 8 | 9 | 10 | /** 11 | * @author: liwh 12 | * @Date: 2017/2/6. 13 | * @Description: 14 | */ 15 | public class IntermediaryChannelHandler extends ChannelInitializer { 16 | 17 | protected void initChannel(SocketChannel ch) throws Exception { 18 | /*--===客户端接收到的是 httpResponse 响应,所以要使用 HttpResponseDecoder 进行解码===--*/ 19 | ch.pipeline().addLast(new HttpResponseDecoder()); 20 | /*--==客户端发送的是 httprequest,所以要使用 HttpRequestEncoder 进行编码==--*/ 21 | ch.pipeline().addLast(new HttpRequestEncoder()); 22 | ch.pipeline().addLast(new ChunkedWriteHandler()); 23 | //ch.pipeline().addLast(new HttpDownloadHandler(local)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial06/TestMethod.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial06; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * @author: liwh 7 | * @Date: 2017/2/6. 8 | * @Description: 9 | */ 10 | public class TestMethod { 11 | public TestMethod() { 12 | try { 13 | //DownFileInfoBean bean = new DownFileInfoBean( 14 | // "D:/lwhSpaces/TemplateRepo/Centos6.7bit64.xva", "S:\\TEMP", 15 | // "Centos6.7bit64.xva", 5,true,null); 16 | 17 | /*----========本地下载=========----*/ 18 | File file = new File("D:\\lwhSpaces\\TemplateRepo\\Centos7.1bit64.xva"); 19 | DownFileInfoBean bean = new DownFileInfoBean(null, "S:\\TEMP", 20 | "Centos6.7bit64.xva", 5,false,file); 21 | DownFileFetch fileFetch = new DownFileFetch(bean); 22 | fileFetch.start(); 23 | } catch (Exception e) { 24 | e.printStackTrace(); 25 | } 26 | } 27 | 28 | public static void main(String[] args) { 29 | new TestMethod(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial02/thread02/TestThread2.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial02.thread02; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * @author: liwh 7 | * @Date: 2017/2/5. 8 | * @Description:测试线程! 9 | */ 10 | public class TestThread2 { 11 | 12 | public static void main(String[] args) { 13 | ReadThread rt =new ReadThread("ceshi001"); 14 | 15 | System.out.println("======================================-----启动线程: "); 16 | rt.start(); 17 | 18 | while(true) { 19 | int r=0; 20 | try { 21 | r =System.in.read(); 22 | } catch (IOException e) { 23 | e.printStackTrace(); 24 | } 25 | if(r =='q'){ 26 | System.out.println("======================================-----暂停线程: "); 27 | rt.suspend(); 28 | } 29 | if(r == 'n'){ 30 | System.out.println("======================================-----继续线程: "); 31 | rt.resume(); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/demo02/ObjectClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.demo02; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | 6 | /** 7 | * @author: liwh 8 | * @Date: 2017/1/12. 9 | * @Description: 10 | */ 11 | public class ObjectClientHandler extends ChannelInboundHandlerAdapter { 12 | @Override 13 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 14 | User user = new User(); 15 | user.setId(1L); 16 | user.setUsername("netty"); 17 | ctx.write(user); 18 | ctx.flush(); 19 | System.out.println("xxx"); 20 | } 21 | 22 | @Override 23 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 24 | User user = (User) msg; 25 | System.out.println(user); 26 | ctx.close(); 27 | } 28 | 29 | @Override 30 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 31 | cause.printStackTrace(); 32 | ctx.close(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.idea/artifacts/nettyy_demo01_war_exploded.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/nettyy-demo01/target/netty-demo01 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /nettyy-demo01/src/main/java/com/lwhtarena/xuchuan/readme.md: -------------------------------------------------------------------------------- 1 | Java 实现断点续传的关键几点 2 | (1) 用什么方法实现提交 RANGE: bytes=2000070-。 3 | 4 | 当然用最原始的 Socket 是肯定能完成的,不过那样太费事了,其实 Java 的 net 包中提供了这种功能。代码如下: 5 | 6 | URL url = new URL("http://www.sjtu.edu.cn/down.zip"); 7 | HttpURLConnection httpConnection = (HttpURLConnection)url.openConnection(); 8 | 9 | // 设置 User-Agent 10 | httpConnection.setRequestProperty("User-Agent","NetFox"); 11 | // 设置断点续传的开始位置 12 | httpConnection.setRequestProperty("RANGE","bytes=2000070"); 13 | // 获得输入流 14 | InputStream input = httpConnection.getInputStream(); 15 | 从输入流中取出的字节流就是 down.zip 文件从 2000070 开始的字节流。 大家看,其实断点续传用 Java 实现起来还是很简单的吧。 接下来要做的事就是怎么保存获得的流到文件中去了。 16 | 17 | (2) 保存文件采用的方法。 18 | 19 | 我采用的是 IO 包中的 RandAccessFile 类。 20 | 操作相当简单,假设从 2000070 处开始保存文件,代码如下: 21 | RandomAccess oSavedFile = new RandomAccessFile("down.zip","rw"); 22 | long nPos = 2000070; 23 | // 定位文件指针到 nPos 位置 24 | oSavedFile.seek(nPos); 25 | byte[] b = new byte[1024]; 26 | int nRead; 27 | // 从输入流中读入字节流,然后写到文件中 28 | while((nRead=input.read(b,0,1024)) > 0) 29 | { 30 | oSavedFile.write(b,0,nRead); 31 | } 32 | 怎么样,也很简单吧。 接下来要做的就是整合成一个完整的程序了。包括一系列的线程控制等等。 33 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial03/model/Process.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial03.model; 2 | 3 | /** 4 | * @author: liwh 5 | * @Date: 2016/11/28. 6 | * @Description: 7 | */ 8 | public class Process { 9 | 10 | private int amount;//量 11 | 12 | private String rate; //进度 13 | 14 | private String speed; //速度 15 | 16 | public Process() { 17 | } 18 | 19 | public int getAmount() { 20 | return amount; 21 | } 22 | 23 | public void setAmount(int amount) { 24 | this.amount = amount; 25 | } 26 | 27 | public String getRate() { 28 | return rate; 29 | } 30 | 31 | public void setRate(String rate) { 32 | this.rate = rate; 33 | } 34 | 35 | public String getSpeed() { 36 | return speed; 37 | } 38 | 39 | public void setSpeed(String speed) { 40 | this.speed = speed; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "Process{" + 46 | "amount=" + amount + 47 | ", rate='" + rate + '\'' + 48 | ", speed='" + speed + '\'' + 49 | '}'; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /netty-file-client/src/main/java/com/lwhtarena/netty/netty4/model/Process.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.netty4.model; 2 | 3 | /** 4 | * @author: liwh 5 | * @Date: 2016/11/28. 6 | * @Description: 7 | */ 8 | public class Process { 9 | 10 | private int amount;//量 11 | 12 | private String rate; //进度 13 | 14 | private String speed; //速度 15 | 16 | public Process() { 17 | } 18 | 19 | public int getAmount() { 20 | return amount; 21 | } 22 | 23 | public void setAmount(int amount) { 24 | this.amount = amount; 25 | } 26 | 27 | public String getRate() { 28 | return rate; 29 | } 30 | 31 | public void setRate(String rate) { 32 | this.rate = rate; 33 | } 34 | 35 | public String getSpeed() { 36 | return speed; 37 | } 38 | 39 | public void setSpeed(String speed) { 40 | this.speed = speed; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "Process{" + 46 | "amount=" + amount + 47 | ", rate='" + rate + '\'' + 48 | ", speed='" + speed + '\'' + 49 | '}'; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/netty4/downServer/HttpChannelInitlalizer.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.netty4.downServer; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.http.HttpObjectAggregator; 7 | import io.netty.handler.codec.http.HttpServerCodec; 8 | import io.netty.handler.stream.ChunkedWriteHandler; 9 | 10 | /** 11 | * @author: liwh 12 | * @Date: 2016/11/17. 13 | * @Description: 14 | */ 15 | public class HttpChannelInitlalizer extends ChannelInitializer { 16 | 17 | @Override 18 | protected void initChannel(SocketChannel ch) throws Exception { 19 | ChannelPipeline pipeline = ch.pipeline(); 20 | pipeline.addLast(new HttpServerCodec()); 21 | 22 | /* 23 | * 不能添加这个,对传输文件 进行了大小的限制。。。。。 24 | */ 25 | // pipeline.addLast("aggregator", new HttpChunkAggregator(6048576)); 26 | 27 | pipeline.addLast(new HttpObjectAggregator(65536)); 28 | pipeline.addLast(new ChunkedWriteHandler()); 29 | pipeline.addLast(new HttpChannelHandler()); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /netty-file-client/netty-file-client.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/tutorial02/RandomAccessFileDemo01.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial02; 2 | 3 | import java.io.FileNotFoundException; 4 | import java.io.IOException; 5 | import java.io.RandomAccessFile; 6 | 7 | /** 8 | * @author: liwh 9 | * @Date: 2017/1/13. 10 | * @Description:RandomAccessFile是用来访问那些保存数据记录的文件的,你就 11 | * 可以用seek( )方法来访问记录,并进行读写了。这些记录的大小不必相同;但是其大小和 12 | * 位置必须是可知的。但是该类仅限于操作文件。 13 | */ 14 | public class RandomAccessFileDemo01 { 15 | public static void main(String[] args) throws IOException { 16 | RandomAccessFile rf = new RandomAccessFile("rtest.dat", "rw"); 17 | for (int i = 0; i < 10; i++) { 18 | //写入基本类型double数据 19 | rf.writeDouble(i * 1.414); 20 | } 21 | rf.close(); 22 | rf = new RandomAccessFile("rtest.dat", "rw"); 23 | //直接将文件指针移到第5个double数据后面 24 | rf.seek(5 * 8); 25 | //覆盖第6个double数据 26 | rf.writeDouble(47.0001); 27 | rf.close(); 28 | rf = new RandomAccessFile("rtest.dat", "r"); 29 | for (int i = 0; i < 10; i++) { 30 | System.out.println("Value " + i + ": " + rf.readDouble()); 31 | } 32 | rf.close(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial02/thread01/Thread1.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial02.thread01; 2 | 3 | /** 4 | * @author: liwh 5 | * @Date: 2017/2/5. 6 | * @Description: 7 | */ 8 | public class Thread1 extends Thread { 9 | private boolean isSleep = true; 10 | private boolean isStop = false; 11 | 12 | public void run() { 13 | while(!isStop) { 14 | if(isSleep) { 15 | try { 16 | Thread.sleep(1); 17 | } catch (InterruptedException e) { 18 | e.printStackTrace(); 19 | } 20 | } else { 21 | System.out.println("Thread: "+Thread.currentThread().getName() + " do someting."); 22 | try { 23 | Thread.sleep(2000); 24 | } catch (InterruptedException e) { 25 | e.printStackTrace(); 26 | } 27 | } 28 | } 29 | System.out.println("Thread: "+Thread.currentThread().getName() + " finished."); 30 | } 31 | 32 | public void setSleep(boolean sleep) { 33 | this.isSleep = sleep; 34 | } 35 | public void setStop(boolean stop) { 36 | this.isStop = stop; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /netty-file-server/src/main/java/com/lwhtarena/netty/netty4/server/FileChannelInitializer.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.netty4.server; 2 | 3 | import com.lwhtarena.netty.netty4.code.NettyMessageDecoder; 4 | import com.lwhtarena.netty.netty4.code.NettyMessageEncoder; 5 | import io.netty.channel.Channel; 6 | import io.netty.channel.ChannelInitializer; 7 | import io.netty.handler.codec.serialization.ClassResolvers; 8 | import io.netty.handler.codec.serialization.ObjectDecoder; 9 | import io.netty.handler.codec.serialization.ObjectEncoder; 10 | 11 | /** 12 | * @author: liwh 13 | * @Date: 2016/11/17. 14 | * @Description: 15 | */ 16 | public class FileChannelInitializer extends ChannelInitializer { 17 | @Override 18 | protected void initChannel(Channel ch) throws Exception { 19 | ch.pipeline().addLast(new ObjectEncoder()); 20 | ch.pipeline().addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.weakCachingConcurrentResolver(null))); // 最大长度 21 | 22 | ch.pipeline().addLast(new NettyMessageDecoder());//设置服务器端的编码和解码 23 | ch.pipeline().addLast(new NettyMessageEncoder()); 24 | 25 | ch.pipeline().addLast(new SecureServerHandler()); 26 | ch.pipeline().addLast(new FileTransferServerHandler()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/tutorial01/HelloServerInitializer.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial01; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelInitializer; 5 | import io.netty.channel.ChannelPipeline; 6 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 7 | import io.netty.handler.codec.Delimiters; 8 | import io.netty.handler.codec.string.StringDecoder; 9 | import io.netty.handler.codec.string.StringEncoder; 10 | 11 | /** 12 | * @author: liwh 13 | * @Date: 2017/1/13. 14 | * @Description:创建和实现HelloServerInitializer 15 | * 实现一个能够像服务端发送文字的功能。服务端假如可以最好还能返回点消息给客户端,然客户端去显示。 16 | */ 17 | public class HelloServerInitializer extends ChannelInitializer { 18 | 19 | protected void initChannel(Channel ch) throws Exception { 20 | ChannelPipeline pipeline =ch.pipeline(); 21 | 22 | // 以("\n")为结尾分割的 解码器 23 | pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); 24 | 25 | // 字符串解码 和 编码 26 | pipeline.addLast("decoder", new StringDecoder()); 27 | pipeline.addLast("encoder", new StringEncoder()); 28 | 29 | // 自己的逻辑Handler 30 | pipeline.addLast("handler", new HelloServerHandler()); 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/tutorial03/server/FileChannelInitializer.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial03.server; 2 | 3 | import com.lwhtarena.netty.tutorial03.code.NettyMessageDecoder; 4 | import com.lwhtarena.netty.tutorial03.code.NettyMessageEncoder; 5 | import io.netty.channel.Channel; 6 | import io.netty.channel.ChannelInitializer; 7 | import io.netty.handler.codec.serialization.ClassResolvers; 8 | import io.netty.handler.codec.serialization.ObjectDecoder; 9 | import io.netty.handler.codec.serialization.ObjectEncoder; 10 | 11 | /** 12 | * @author: liwh 13 | * @Date: 2016/11/17. 14 | * @Description: 15 | */ 16 | public class FileChannelInitializer extends ChannelInitializer { 17 | @Override 18 | protected void initChannel(Channel ch) throws Exception { 19 | ch.pipeline().addLast(new ObjectEncoder()); 20 | ch.pipeline().addLast(new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.weakCachingConcurrentResolver(null))); // 最大长度 21 | 22 | ch.pipeline().addLast(new NettyMessageDecoder());//设置服务器端的编码和解码 23 | ch.pipeline().addLast(new NettyMessageEncoder()); 24 | 25 | ch.pipeline().addLast(new SecureServerHandler()); 26 | ch.pipeline().addLast(new FileTransferServerHandler()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/tutorial03/readme.md: -------------------------------------------------------------------------------- 1 | # netty4.x 超大文件传输,基于基于http 2 | 3 | 【实现原理:】 4 | 5 | - 1.文件分片传输 6 | - 2.MD5校验服务器文件是否存在 7 | - 3.断点续传 8 | - 4.上传权限校验等功能。 9 | 10 | 为了实现上面四点,做下实现的思路: 11 | 12 | 1.文件的分片上传主要用到了RandomAccessFile类,这个类支持读取文件的起始地设置,以及读取字节长度等; 13 | 由这个类我们就可以把 文件分成n分(n取决于你每个包想设置多大),每一份上传成功后,服务端开始写到服务 14 | 文件里面,然后返回客户端下一个包的文件读取 开始位置以此类推,一直到文件读取完成,服务端返回客户端下 15 | 载文件的路径(每上传成功一个包,会返回客户端上传的进度百分比)。 16 | 17 | 2.MD5校验,主要是客户端读取文件内容然后把内容生产一个MD5,在上传文件的时候把MD5值也附加在里面。服务 18 | 端收到后会先验证MD5值在 服务端是否已经存在,存在则直接返回文件下载地址,并标记上传进度为 100% 19 | 20 | 3.断点续传也是基于MD5来判断,服务端发现客户端上传的文件服务端存在,但是这个时候比较客户端文件总长度和 21 | 服务端已经存在文件的总长度 不一致,这个时候如果客户端的文件长度大于服务端则认为文件需要续传,返回客户 22 | 端现在服务端的文件写入到的位置,让客户端继续接着位置开始 23 | 24 | 4.上传权限主要是用来防止客户端恶意上传文件,因为本服务需要对外,不能让没有权限的人知道地址和端口就可以 25 | 随意上传。netty支持hander的有序 拦截处理,所以我在这里是把权限验证放第一个hander,客户端连接支持必须 26 | 发一个权限验证包,比如把登录后的token传入到服务端,服务端进行验证 token有效性,返回客户端是否验证成功, 27 | 并把当前连接加入已验证通过列表。下次上传的包验证通过后直接进入下一个hander处理即可 28 | 29 | 在实现功能的时候需要注意以下: 30 | 1.传输过程是否支持夸平台(因为服务端对应的客户端有很多如php、java、object-c、.net等) 31 | 2.传输内容的编解码 32 | 3.粘包、拆包(netty默认支持,这里就不考虑了啊) 33 | 34 | 35 | 本文实现过程中,传输的内容采用的json格式,最开始之间传输用java的序列化来实现的,发现如果客户端是别的语 36 | 言就无法使用了,所以就采用了json格式。 当然我建议大家使用Google的 Protocol Buffers 或者 facebook的 37 | Thrift,他们的性能开销是json的1/4不到,大小是json的1/4不到。使用thrift可以参考开 源项目nifty,这个 38 | 项目也是Facebook开源出来的。 -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial01/HelloClientInitializer.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial01; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.DelimiterBasedFrameDecoder; 7 | import io.netty.handler.codec.Delimiters; 8 | import io.netty.handler.codec.string.StringDecoder; 9 | import io.netty.handler.codec.string.StringEncoder; 10 | 11 | /** 12 | * @author: liwh 13 | * @Date: 2017/1/13. 14 | * @Description: 15 | */ 16 | public class HelloClientInitializer extends ChannelInitializer { 17 | 18 | @Override 19 | protected void initChannel(SocketChannel ch) throws Exception { 20 | ChannelPipeline pipeline = ch.pipeline(); 21 | 22 | /** 23 | * 这个地方的 必须和服务端对应上。否则无法正常解码和编码 24 | * 25 | * 解码和编码 我将会在下一张为大家详细的讲解。再次暂时不做详细的描述 26 | * 27 | * */ 28 | pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); 29 | pipeline.addLast("decoder", new StringDecoder()); 30 | pipeline.addLast("encoder", new StringEncoder()); 31 | 32 | // 客户端的逻辑 33 | pipeline.addLast("handler", new HelloClientHandler()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /netty-file-client/src/test/java/com/lwhtarena/netty/ThreadPool.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | 6 | public class ThreadPool { 7 | 8 | private static ExecutorService executorService; 9 | 10 | private ThreadPool() { 11 | } 12 | 13 | public static void addWork(final QueueTask task) { 14 | //创建一个可重用固定线程数的线程池 15 | if (executorService == null) { 16 | synchronized (ThreadPool.class) { 17 | if (executorService == null) { 18 | /*executorService = new ThreadPoolExecutor(2, 1024, 19 | 60L, TimeUnit.SECONDS, workQueue);*/ 20 | executorService = Executors.newCachedThreadPool(); 21 | } 22 | } 23 | } 24 | 25 | executorService.execute(new Runnable() { 26 | public void run() { 27 | // TODO Auto-generated method stub 28 | try { 29 | task.executeTask(); 30 | } catch (Exception e) { 31 | e.printStackTrace(); 32 | } 33 | } 34 | }); 35 | } 36 | 37 | public static void shutdown() { 38 | executorService.shutdown(); 39 | } 40 | } -------------------------------------------------------------------------------- /netty-bigFile/src/main/java/com/lwhtarena/netty/bigFile/server/HttpChannelInitlalizer.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.bigFile.server; 2 | 3 | import io.netty.channel.ChannelInitializer; 4 | import io.netty.channel.ChannelPipeline; 5 | import io.netty.channel.socket.SocketChannel; 6 | import io.netty.handler.codec.http.HttpObjectAggregator; 7 | import io.netty.handler.codec.http.HttpServerCodec; 8 | import io.netty.handler.stream.ChunkedWriteHandler; 9 | 10 | /** 11 | * @author: liwh 12 | * @Date: 2016/11/17. 13 | * @Description: 14 | */ 15 | public class HttpChannelInitlalizer extends ChannelInitializer { 16 | 17 | @Override 18 | protected void initChannel(SocketChannel ch) throws Exception { 19 | ChannelPipeline pipeline = ch.pipeline(); 20 | pipeline.addLast(new HttpServerCodec()); 21 | 22 | /* 23 | * 不能添加这个,对传输文件 进行了大小的限制。。。。。 24 | */ 25 | // pipeline.addLast("aggregator", new HttpChunkAggregator(6048576)); 26 | 27 | pipeline.addLast(new HttpObjectAggregator(65536)); 28 | 29 | /**--==加入chunked 主要作用是支持异步发送的码流(大文件传输),但不占用过多的内存,防止java内存溢出==--**/ 30 | pipeline.addLast(new ChunkedWriteHandler()); 31 | 32 | /**--==加入自定义处理文件服务器的业务逻辑handler==--**/ 33 | pipeline.addLast(new HttpChannelHandler()); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/demo01/HttpClientInboundHandler.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.demo01; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelInboundHandlerAdapter; 6 | import io.netty.handler.codec.http.HttpContent; 7 | import io.netty.handler.codec.http.HttpHeaders; 8 | import io.netty.handler.codec.http.HttpResponse; 9 | 10 | /** 11 | * @author: liwh 12 | * @Date: 2017/1/12. 13 | * @Description: 处理Server响应的HttpClientInboundHandler 14 | */ 15 | public class HttpClientInboundHandler extends ChannelInboundHandlerAdapter { 16 | 17 | @Override 18 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 19 | if (msg instanceof HttpResponse) { 20 | HttpResponse response = (HttpResponse) msg; 21 | System.out.println("CONTENT_TYPE:" + response.headers().get(HttpHeaders.Names.CONTENT_TYPE)); 22 | System.out.println("========================="); 23 | } 24 | if (msg instanceof HttpContent) { 25 | HttpContent content = (HttpContent) msg; 26 | ByteBuf buf = content.content(); 27 | System.out.println(buf.toString(io.netty.util.CharsetUtil.UTF_8)); 28 | buf.release(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /nettyy-demo01/src/main/java/com/lwhtarena/netty/netty/readme.md: -------------------------------------------------------------------------------- 1 | ## 用MD5验证上传文件的完整性 2 | 3 | 在项目的开发资源开发中,测试发现一个问题:将资源上传到服务器上,提示已经上传成功,但是当打开这个文件时发现失败,由于各种原因资源已经毁坏。怎么样能保证资源的完整性,处理办法就是用MD5验证文件的完整性。 4 | 5 | 任何一个字符串或文件,无论是可执行程序、图像文件、临时文件或者其他任何类型的文件,也不管它体积多大,都有且只有一个独一无二的MD5信息码,并且如果这个文件被修改过,它的MD5码也将随之改变。 6 | 7 | 8 | 断点意味着网络会断,然后断了之后,服务端根本获取不到本次上传的内容,于是下次又只能从头开始传文件。一种解决办法是客户端将文件分成很小的片段(单个片段丢了就整个片段重传),这个方案要求客户端做很多工作,服务端还得根据片段的编号组织文件,总之客户端和服务端都挺麻烦。 9 | 10 | 于是就想到用netty在写一个服务filestoreApdapterServer,文件上传提交给这个代理服务。这个做法有个前提就是,客户端上传的文件名称保证唯一,并且在请求头里面带着这个名字,以便服务端定位文件。利用的原理是一般长度比较大的消息体,netty会使用chunk传输,我们取得chunk写入临时文件,这样即使网络断了,服务端已经获取的文件内容还是保留在临时文件里面。 11 | 12 | 流程如下: 13 | 14 | 1. filestoreApdapterServer将请求的消息体写到临时文件(网络断了也不要紧,读到多少写多少)。 15 | 16 | 2. 客户端下次传之前先调用getSize获取上传传递的文件长度,我们就在这个getSize方法里面偷偷的将第一步保存的临时文件追加到正式文件里面,然后返回文件长度。 17 | 18 | 3. 客户端根据获取的服务端文件长度,定位未传的文件位置,读取上传。重复1,2步骤。直到文件上传完成。 19 | 20 | ## 如何防止MD5秒传 21 | 22 | ### 1.秒传的原理的详细解释 23 | 24 | 上传到网盘的每个文件,服务器都会校验MD5码。如果这个您上传的文件MD5码与已经存在于服务器里的文件的MD5码相同的话,网盘服务器将会判断成为重复文件,只需要复制副本保存在网盘上即可,无需重新保存,因为有过目前这个文件,于是很快完成上传任务,并在有人需要下载的时候将原有的该文件的下载地址放出。这样实现了服务器的高效运作。 25 | 26 | ### 2.怎样不秒传? 27 | 28 | 把你要上传的东西压缩成RAR,东西上传,服务器会先做MD5校验,如果服务器上有一样的东西,它就直接给你个新地址,其实你下载的都是服务器上的同一个文件,想要不秒传,其实只要让MD5改变,就是对文件本身做一下修改(改名字不行),例如一个文本文件,你多加几个字,MD5就变了,就不会秒传了。 但是有些文件我们不好改变,也不想改变,那其实只要压缩一下,MD5就变了, 29 | 30 | 而下载的人也能获得最原始的资料,不过就是加压要花费一点时间。 -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial05/module/BaseMsg.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial05.module; 2 | 3 | import com.lwhtarena.netty.tutorial05.module.enums.MsgType; 4 | 5 | import java.io.Serializable; 6 | import java.util.Date; 7 | 8 | 9 | /** 10 | * 11 | */ 12 | public abstract class BaseMsg implements Serializable { 13 | private static final long serialVersionUID = 7884485597941697632L; 14 | private MsgType type; 15 | //必须唯一,否者会出现channel调用混乱 16 | private String clientId; 17 | private long dateTime; 18 | //初始化客户端id 19 | public BaseMsg(String clientId) { 20 | this.clientId = clientId; 21 | this.dateTime = new Date().getTime(); 22 | } 23 | 24 | public String getClientId() { 25 | return clientId; 26 | } 27 | 28 | public void setClientId(String clientId) { 29 | this.clientId = clientId; 30 | } 31 | 32 | public MsgType getType() { 33 | return type; 34 | } 35 | 36 | public void setType(MsgType type) { 37 | this.type = type; 38 | } 39 | 40 | public long getDateTime() { 41 | return dateTime; 42 | } 43 | 44 | public void setDateTime(long dateTime) { 45 | this.dateTime = dateTime; 46 | } 47 | 48 | @Override 49 | public String toString() { 50 | return "Msg [type=" + type + ", clientId=" + clientId + ", dateTime=" + dateTime + "]"; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /netty-bigFile/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.lwhtarena.netty 6 | netty-bigFile 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | netty-bigFile 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | 19 | junit 20 | junit 21 | 3.8.1 22 | test 23 | 24 | 25 | io.netty 26 | netty-transport 27 | 4.1.4.Final 28 | 29 | 30 | io.netty 31 | netty-codec-http 32 | 4.1.4.Final 33 | 34 | 35 | io.netty 36 | netty-handler 37 | 4.1.4.Final 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /netty-file-client/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.lwhtarena.netty 6 | netty-file-client 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | netty-file-client 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | 19 | junit 20 | junit 21 | 3.8.1 22 | test 23 | 24 | 25 | io.netty 26 | netty-all 27 | 4.0.23.Final 28 | 29 | 30 | 31 | org.slf4j 32 | slf4j-api 33 | 1.6.6 34 | 35 | 36 | 37 | com.alibaba 38 | fastjson 39 | 1.2.2 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /nettyy-demo01/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.lwhtarena 5 | netty-demo01 6 | war 7 | 1.0-SNAPSHOT 8 | netty-demo01 Maven Webapp 9 | http://maven.apache.org 10 | 11 | 12 | junit 13 | junit 14 | 3.8.1 15 | test 16 | 17 | 18 | 19 | 20 | io.netty 21 | netty-all 22 | 4.1.6.Final 23 | compile 24 | 25 | 26 | 27 | org.slf4j 28 | slf4j-api 29 | 1.6.6 30 | 31 | 32 | 33 | com.alibaba 34 | fastjson 35 | 1.2.2 36 | 37 | 38 | 39 | 40 | 41 | netty-demo01 42 | 43 | 44 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial03/test/LargeMappedFiles.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial03.test; 2 | 3 | import java.io.RandomAccessFile; 4 | import java.nio.MappedByteBuffer; 5 | import java.nio.channels.FileChannel; 6 | 7 | /** 8 | * @author: liwh 9 | * @Date: 2017/1/17. 10 | * @Description: 11 | */ 12 | public class LargeMappedFiles { 13 | 14 | static int length = 0x8FFFFFF; // 128 Mb 15 | 16 | public static void main(String[] args) throws Exception { 17 | MappedByteBuffer out = new RandomAccessFile("D:/lwhSpaces/TemplateRepo/windows2008.xva", "rw").getChannel().map(FileChannel.MapMode.READ_WRITE, 0, length); 18 | for (int i = 0; i < length; i++) 19 | out.put((byte) 'x'); 20 | System.out.println("Finished writing "); 21 | for (int i = length / 2; i < length / 2 + 6; i++) 22 | System.out.print((char) out.get(i)); // read file 23 | } 24 | } 25 | 26 | /** 27 | * 说明: 28 | * RandomAccessFile类:支持对随机存取文件的读取和写入。随机存取文件的行为类似存储在文件系统中的一个大型字节数组。 29 | * FileChannel:用于读取、写入、映射和操作文件的通道。 30 | * MappedByteBuffer:直接字节缓冲区,其内容是文件的内存映射区域。 参数部分: 31 | * FileChannel.MapMode.READ_WRITE(mode) - 根据是按只读、读取/写入或专用(写入时拷贝)来映射文件,分别为 FileChannel.MapMode 类中所定义的 READ_ONLY、READ_WRITE 或 PRIVATE 之一; 32 | * 0(position) - 文件中的位置,映射区域从此位置开始;必须为非负数 ; 33 | * length(size) - 要映射的区域大小;必须为非负数且不大于 Integer.MAX_VALUE //这个值你设置得太大了,2个G的文件你全部映射到内存中来了。 34 | * 35 | * */ -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/tutorial02/MapMemeryBuffer01.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial02; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.FileOutputStream; 5 | import java.nio.ByteBuffer; 6 | import java.nio.channels.FileChannel; 7 | 8 | /** 9 | * @author: liwh 10 | * @Date: 2017/1/16. 11 | * @Description:MappedByteBuffer的读取/写入文件和普通I/O流的对比 12 | */ 13 | public class MapMemeryBuffer01 { 14 | 15 | public static void main(String[] args) throws Exception{ 16 | ByteBuffer byteBuf = ByteBuffer.allocate(1024 * 14 * 1024); 17 | 18 | byte[] bbb = new byte[14 * 1024 * 1024]; 19 | 20 | FileInputStream fis = new FileInputStream("D:\\Test\\test"); 21 | 22 | FileOutputStream fos = new FileOutputStream("D:\\Test\\test\\outFile.txt"); 23 | 24 | FileChannel fc = fis.getChannel(); 25 | 26 | long timeStar = System.currentTimeMillis();//得到当前的时间 27 | 28 | fc.read(byteBuf);//1 读取 29 | 30 | long timeEnd = System.currentTimeMillis();//得到当前的时间 31 | 32 | System.out.println("Read time :" + (timeEnd - timeStar) + "ms"); 33 | 34 | timeStar = System.currentTimeMillis(); 35 | 36 | fos.write(bbb);// 写入 37 | 38 | timeEnd = System.currentTimeMillis(); 39 | 40 | System.out.println("Write time :" + (timeEnd - timeStar) + "ms"); 41 | 42 | fos.flush(); 43 | 44 | fc.close(); 45 | 46 | fis.close(); 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/heartbeat/asdsad.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.heartbeat; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import io.netty.channel.ChannelHandlerContext; 6 | import io.netty.channel.ChannelInboundHandlerAdapter; 7 | import io.netty.util.HashedWheelTimer; 8 | import io.netty.util.Timeout; 9 | import io.netty.util.Timer; 10 | import io.netty.util.TimerTask; 11 | 12 | public class asdsad extends ChannelInboundHandlerAdapter implements TimerTask { 13 | 14 | private final Timer timer=new HashedWheelTimer(); 15 | 16 | private volatile boolean reconnect = true; 17 | 18 | @Override 19 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 20 | 21 | System.out.println("当前链路已经激活了,重连尝试次数重新置为0"); 22 | 23 | API.attempts = 0; 24 | ctx.fireChannelActive(); 25 | } 26 | 27 | @Override 28 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 29 | System.out.println("链接关闭"); 30 | ctx.close(); 31 | if(reconnect){ 32 | System.out.println("链接关闭,将进行重连"+API.attempts); 33 | if (API.attempts < 12) { 34 | API.attempts++; 35 | int timeout = 2 << API.attempts; 36 | timer.newTimeout(this, timeout, TimeUnit.MILLISECONDS); 37 | } else{ 38 | System.out.println("等待主动触发重连");//主动触发需要将API.attempts清零并调用NettyClient.doConnect() 39 | } 40 | 41 | } 42 | } 43 | 44 | public void run(Timeout timeout) throws Exception { 45 | NettyClient.doConnect(); //延时重连 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /nettyy-demo01/src/main/java/com/lwhtarena/xuchuan/SiteInfoBean.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.xuchuan; 2 | 3 | /** 4 | * @author: liwh 5 | * @Date: 2017/2/6. 6 | * @Description:要抓取的文件的信息,如文件保存的目录,名字,抓取文件的 URL 等 7 | */ 8 | public class SiteInfoBean { 9 | private String sSiteURL; //Site's URL 10 | private String sFilePath; //Saved File's Path 11 | private String sFileName; //Saved File's Name 12 | private int nSplitter; //Count of Splited Downloading File 13 | 14 | public SiteInfoBean() { 15 | //default value of nSplitter is 5 16 | this("", "", "", 5); 17 | } 18 | 19 | public SiteInfoBean(String sURL, String sPath, String sName, int nSpiltter) { 20 | sSiteURL = sURL; 21 | sFilePath = sPath; 22 | sFileName = sName; 23 | this.nSplitter = nSpiltter; 24 | } 25 | 26 | public String getSSiteURL() { 27 | return sSiteURL; 28 | } 29 | 30 | public void setSSiteURL(String value) { 31 | sSiteURL = value; 32 | } 33 | 34 | public String getSFilePath() { 35 | return sFilePath; 36 | } 37 | 38 | public void setSFilePath(String value) { 39 | sFilePath = value; 40 | } 41 | 42 | public String getSFileName() { 43 | return sFileName; 44 | } 45 | 46 | public void setSFileName(String value) { 47 | sFileName = value; 48 | } 49 | 50 | public int getNSplitter() { 51 | return nSplitter; 52 | } 53 | 54 | public void setNSplitter(int nCount) { 55 | nSplitter = nCount; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/tutorial02/MapMemeryBuffer02.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial02; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.FileOutputStream; 5 | import java.nio.ByteBuffer; 6 | import java.nio.MappedByteBuffer; 7 | import java.nio.channels.FileChannel; 8 | 9 | /** 10 | * @author: liwh 11 | * @Date: 2017/1/16. 12 | * @Description:MappedByteBuffer的读取/写入文件和普通I/O流的对比 13 | */ 14 | public class MapMemeryBuffer02 { 15 | 16 | public static void main(String[] args) throws Exception{ 17 | ByteBuffer byteBuf = ByteBuffer.allocate(1024 * 14 * 1024); 18 | 19 | byte[] bbb = new byte[14 * 1024 * 1024]; 20 | 21 | FileInputStream fis = new FileInputStream("d:\\test"); 22 | 23 | FileOutputStream fos = new FileOutputStream("d:\\outFile.txt"); 24 | 25 | FileChannel fc = fis.getChannel(); 26 | 27 | long timeStar = System.currentTimeMillis();//得到当前的时间 28 | 29 | MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());//1 读取 30 | 31 | long timeEnd = System.currentTimeMillis();//得到当前的时间 32 | 33 | System.out.println("Read time :" + (timeEnd - timeStar) + "ms"); 34 | 35 | timeStar = System.currentTimeMillis(); 36 | 37 | //fos.write(bbb);// 写入 38 | mbb.flip(); 39 | 40 | timeEnd = System.currentTimeMillis(); 41 | 42 | System.out.println("Write time :" + (timeEnd - timeStar) + "ms"); 43 | 44 | fos.flush(); 45 | 46 | fc.close(); 47 | 48 | fis.close(); 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial06/DownFileAccess.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial06; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.RandomAccessFile; 6 | import java.io.Serializable; 7 | 8 | /** 9 | * @author: liwh 10 | * @Date: 2017/2/6. 11 | * @Description:文件对象 12 | */ 13 | public class DownFileAccess implements Serializable{ 14 | private static final long serialVersionUID = -2518013155676212866L; 15 | //写入文件的流 16 | RandomAccessFile oSavedFile; 17 | //开始位置 18 | long nPos; 19 | boolean bFirst; 20 | 21 | public DownFileAccess() throws IOException { 22 | this("", 0,true); 23 | } 24 | 25 | /** 26 | * 写入文件初始化 27 | * @param sName 28 | * @param nPos 29 | * @throws IOException 30 | */ 31 | public DownFileAccess(String sName, long nPos,boolean bFirst) throws IOException { 32 | File wfile = new File(sName); 33 | oSavedFile = new RandomAccessFile(wfile,"rw"); 34 | if(!bFirst){ 35 | oSavedFile.seek(wfile.length()); 36 | } 37 | this.nPos = nPos; 38 | this.bFirst = bFirst; 39 | } 40 | 41 | /** 42 | * 写文件 43 | * @param b 44 | * @param nStart 45 | * @param nLen 46 | * @return 47 | */ 48 | public synchronized int write(byte[] b, int nStart, int nLen) { 49 | int n = -1; 50 | try { 51 | oSavedFile.write(b, nStart, nLen); 52 | n = nLen; 53 | } catch (IOException e) { 54 | e.printStackTrace(); 55 | } 56 | return n; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /netty-bigFile/netty-bigFile.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /nettyy-demo01/src/main/java/com/lwhtarena/netty/基本案例01/echo/server/EchoServerHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package com.lwhtarena.netty.基本案例01.echo.server; 17 | 18 | import io.netty.channel.ChannelHandler.Sharable; 19 | import io.netty.channel.ChannelHandlerContext; 20 | import io.netty.channel.ChannelInboundHandlerAdapter; 21 | 22 | /** 23 | * Handler implementation for the echo server. 24 | */ 25 | @Sharable 26 | public class EchoServerHandler extends ChannelInboundHandlerAdapter { 27 | 28 | @Override 29 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 30 | ctx.write(msg); 31 | } 32 | 33 | @Override 34 | public void channelReadComplete(ChannelHandlerContext ctx) { 35 | ctx.flush(); 36 | } 37 | 38 | @Override 39 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 40 | // Close the connection when an exception is raised. 41 | cause.printStackTrace(); 42 | ctx.close(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial02/httpClient/ClientAbortMethod.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial02.httpClient; 2 | 3 | import org.apache.http.client.methods.CloseableHttpResponse; 4 | import org.apache.http.client.methods.HttpGet; 5 | import org.apache.http.impl.client.CloseableHttpClient; 6 | import org.apache.http.impl.client.HttpClients; 7 | 8 | import java.io.IOException; 9 | 10 | /** 11 | * @author: liwh 12 | * @Date: 2017/2/5. 13 | * @Description:这个例子演示了如何中止一个HTTP请求。 14 | * 15 | * 16 | */ 17 | public class ClientAbortMethod { 18 | 19 | public static void main(String[] args) { 20 | CloseableHttpClient httpClient = HttpClients.createDefault(); 21 | try { 22 | HttpGet httpget =new HttpGet("http://www.baidu.com"); 23 | 24 | System.out.println("Executing request " + httpget.getURI()); 25 | CloseableHttpResponse response = httpClient.execute(httpget); 26 | 27 | try { 28 | System.out.println("----------------------------------------"); 29 | System.out.println(response.getStatusLine()); 30 | // Do not feel like reading the response body 31 | // Call abort on the request object 32 | httpget.abort(); 33 | }finally { 34 | response.close(); 35 | } 36 | 37 | } catch (IOException e) { 38 | e.printStackTrace(); 39 | }finally { 40 | try { 41 | httpClient.close(); 42 | } catch (IOException e) { 43 | e.printStackTrace(); 44 | } 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /netty-bigFile/src/main/java/com/lwhtarena/netty/bigFile/server/HttpFileListenServerBootstarp.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.bigFile.server; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioServerSocketChannel; 8 | 9 | /** 10 | * @author: liwh 11 | * @Date: 2016/11/17. 12 | * @Description: 13 | */ 14 | public class HttpFileListenServerBootstarp implements Runnable { 15 | private int port; 16 | 17 | public HttpFileListenServerBootstarp(int port) { 18 | super(); 19 | this.port = port; 20 | } 21 | 22 | public void run() { 23 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); 24 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 25 | ServerBootstrap serverBootstrap = new ServerBootstrap(); 26 | serverBootstrap.group(bossGroup, workerGroup); 27 | serverBootstrap.channel(NioServerSocketChannel.class); 28 | 29 | serverBootstrap.childHandler(new HttpChannelInitlalizer()); 30 | try { 31 | ChannelFuture f = serverBootstrap.bind(port).sync(); 32 | f.channel().closeFuture().sync(); 33 | } catch (InterruptedException e) { 34 | e.printStackTrace(); 35 | } finally { 36 | bossGroup.shutdownGracefully(); 37 | workerGroup.shutdownGracefully(); 38 | } 39 | } 40 | 41 | public static void main(String[] args) { 42 | HttpFileListenServerBootstarp serve =new HttpFileListenServerBootstarp(9003); 43 | serve.run(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /nettyy-demo01/nettyy-demo01.iml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/netty4/downServer/HttpFileListenServerBootstarp.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.netty4.downServer; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioServerSocketChannel; 8 | 9 | /** 10 | * @author: liwh 11 | * @Date: 2016/11/17. 12 | * @Description: 13 | */ 14 | public class HttpFileListenServerBootstarp implements Runnable { 15 | private int port; 16 | 17 | public HttpFileListenServerBootstarp(int port) { 18 | super(); 19 | this.port = port; 20 | } 21 | 22 | public void run() { 23 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); 24 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 25 | ServerBootstrap serverBootstrap = new ServerBootstrap(); 26 | serverBootstrap.group(bossGroup, workerGroup); 27 | serverBootstrap.channel(NioServerSocketChannel.class); 28 | 29 | //serverBootstrap.handler(new LoggingHandler(LogLevel.INFO)); 30 | serverBootstrap.childHandler(new HttpChannelInitlalizer()); 31 | try { 32 | ChannelFuture f = serverBootstrap.bind(port).sync(); 33 | f.channel().closeFuture().sync(); 34 | } catch (InterruptedException e) { 35 | e.printStackTrace(); 36 | } finally { 37 | bossGroup.shutdownGracefully(); 38 | workerGroup.shutdownGracefully(); 39 | } 40 | } 41 | 42 | public static void main(String[] args) { 43 | HttpFileListenServerBootstarp serve =new HttpFileListenServerBootstarp(9003); 44 | serve.run(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /netty-file-server/netty-file-server.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/demo02/ObjectClient.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.demo02; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioSocketChannel; 11 | import io.netty.handler.codec.serialization.ClassResolvers; 12 | import io.netty.handler.codec.serialization.ObjectDecoder; 13 | import io.netty.handler.codec.serialization.ObjectEncoder; 14 | 15 | /** 16 | * @author: liwh 17 | * @Date: 2017/1/12. 18 | * @Description: 19 | */ 20 | public class ObjectClient { 21 | public static void main(String[] args) throws InterruptedException { 22 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 23 | try { 24 | Bootstrap b = new Bootstrap(); 25 | b.group(workerGroup) 26 | .channel(NioSocketChannel.class) 27 | .option(ChannelOption.SO_KEEPALIVE, true) 28 | .handler(new ChannelInitializer() { 29 | @Override 30 | protected void initChannel(SocketChannel ch) throws Exception { 31 | ch.pipeline().addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(this.getClass().getClassLoader())),new ObjectEncoder(), new ObjectClientHandler()); 32 | } 33 | }); 34 | ChannelFuture f = b.connect("127.0.0.1", 7777).sync(); 35 | f.channel().closeFuture().sync(); 36 | } finally { 37 | workerGroup.shutdownGracefully(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /netty-file-server/src/main/java/com/lwhtarena/netty/netty4/model/RequestFile.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.netty4.model; 2 | 3 | /** 4 | * @author: liwh 5 | * @Date: 2016/11/17. 6 | * @Description: 7 | */ 8 | public class RequestFile { 9 | 10 | private String file_name;// 文件名 11 | private long starPos;// 开始位置 12 | private byte[] bytes;// 文件字节数组 13 | private int endPos;// 结尾位置 14 | private String file_md5; //文件的MD5值 15 | private String file_type; //文件类型 16 | private long file_size; //文件总长度 17 | 18 | public RequestFile() { 19 | } 20 | 21 | public long getStarPos() { 22 | return starPos; 23 | } 24 | 25 | public void setStarPos(long starPos) { 26 | this.starPos = starPos; 27 | } 28 | 29 | public int getEndPos() { 30 | return endPos; 31 | } 32 | 33 | public void setEndPos(int endPos) { 34 | this.endPos = endPos; 35 | } 36 | 37 | public byte[] getBytes() { 38 | return bytes; 39 | } 40 | 41 | public void setBytes(byte[] bytes) { 42 | this.bytes = bytes; 43 | } 44 | 45 | public String getFile_md5() { 46 | return file_md5; 47 | } 48 | 49 | public void setFile_md5(String file_md5) { 50 | this.file_md5 = file_md5; 51 | } 52 | 53 | public String getFile_name() { 54 | return file_name; 55 | } 56 | 57 | public void setFile_name(String file_name) { 58 | this.file_name = file_name; 59 | } 60 | 61 | public String getFile_type() { 62 | return file_type; 63 | } 64 | 65 | public void setFile_type(String file_type) { 66 | this.file_type = file_type; 67 | } 68 | 69 | public long getFile_size() { 70 | return file_size; 71 | } 72 | 73 | public void setFile_size(long file_size) { 74 | this.file_size = file_size; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/tutorial03/model/RequestFile.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial03.model; 2 | 3 | /** 4 | * @author: liwh 5 | * @Date: 2016/11/17. 6 | * @Description: 7 | */ 8 | public class RequestFile { 9 | 10 | private String file_name;// 文件名 11 | private long starPos;// 开始位置 12 | private byte[] bytes;// 文件字节数组 13 | private int endPos;// 结尾位置 14 | private String file_md5; //文件的MD5值 15 | private String file_type; //文件类型 16 | private long file_size; //文件总长度 17 | 18 | public RequestFile() { 19 | } 20 | 21 | public long getStarPos() { 22 | return starPos; 23 | } 24 | 25 | public void setStarPos(long starPos) { 26 | this.starPos = starPos; 27 | } 28 | 29 | public int getEndPos() { 30 | return endPos; 31 | } 32 | 33 | public void setEndPos(int endPos) { 34 | this.endPos = endPos; 35 | } 36 | 37 | public byte[] getBytes() { 38 | return bytes; 39 | } 40 | 41 | public void setBytes(byte[] bytes) { 42 | this.bytes = bytes; 43 | } 44 | 45 | public String getFile_md5() { 46 | return file_md5; 47 | } 48 | 49 | public void setFile_md5(String file_md5) { 50 | this.file_md5 = file_md5; 51 | } 52 | 53 | public String getFile_name() { 54 | return file_name; 55 | } 56 | 57 | public void setFile_name(String file_name) { 58 | this.file_name = file_name; 59 | } 60 | 61 | public String getFile_type() { 62 | return file_type; 63 | } 64 | 65 | public void setFile_type(String file_type) { 66 | this.file_type = file_type; 67 | } 68 | 69 | public long getFile_size() { 70 | return file_size; 71 | } 72 | 73 | public void setFile_size(long file_size) { 74 | this.file_size = file_size; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/readme.md: -------------------------------------------------------------------------------- 1 | # netty 4.x & netty 3.x 2 | 3 | Netty创建全部都是实现自AbstractBootstrap。客户端的是Bootstrap,服务端的则是ServerBootstrap。 4 | 5 | EventLoopGroup 是在4.x版本中提出来的一个新概念。用于channel的管理。服务端需要两个。和3.x版本一样,一个是boss线程一个是worker线程。 6 | 7 | ## HandlerInitializer详解(很重要) 8 | 9 | ### Handler在Netty中是一个比较重要的概念。有着相当重要的作用。相比于Netty的底层。我们接触更多的应该是他的Handler。 10 | 11 | ---------------------------------------------------------- 12 | 13 | ## 在4.x版本中的ChannelHandler 14 | 15 | ChannelHandler接口是Handler里面的最高的接口。 16 | 17 | ChannelInboundHandler接口和ChannelOutboundHandler接口,继承ChannelHandler接口。 18 | 19 | ChannelInBoundHandler负责数据进入并在ChannelPipeline中按照从上至下的顺序查找调用相应的InBoundHandler。 20 | ChannelOutBoundHandler负责数据出去并在ChannelPipeline中按照从下至上的顺序查找调用相应的OutBoundHandler。 21 | 22 | ## 在5.x版本中的改动 23 | 24 | ChannelInboundHandler和ChannelOutboundHandler接口合并到ChannelHandler里面。 25 | 26 | ChannelInboundHandlerAdapter,ChannelOutboundHandlerAdapter以及ChannelDuplexHandlerAdapter被取消,其功能被ChannelHandlerAdapter代替。 27 | 28 | 由于上述的改动,开发者将无法区分InBoundHandler和OutBoundHandler 所以CombinedChannelDuplexHandler 的功能也被ChannelHandlerAdapter代替。 29 | 30 | 5.x版本中虽然删除了InBoundHandler和OutBoundHandler,但是在设计思想上InBound和OurBound的概念还是存在的。只不过是作者使用了另外一种方式去实现罢了。 31 | 32 | 查看过4.x版本代码的朋友可能已经了解知道了。消息在管道中都是以ChannelHandlerContext的形势传递的。而InBound和OutBound主要作用是被当做ChannelPipeline管道中标识。用于Handler中相对应的调用处理,通过两个布尔值变量inBound和outBound来区分是进入还是出去。并以此来区分Handler并调用相应的方法,其实没有什么实际用途。于是作者在5.x版本中对此做出了优化。优化方案笔者感觉very nice。 33 | 34 | 由于删除了InBoundHandler和OutBoundHandler的接口。作者在DefaultChannelHandlerContext中重写了findContextInBound()和findContextOutBound()方法。并且在方法里引入了参数mask。 35 | 36 | 在类开始处定义静态终态的变量来标记4.x版本中定义的InBound和OutBound中的方法名(可以变相的认为是枚举)。在源代码中的实现是利用mask来获取对应的flag,最终实现使用mask来区分InBoundHandler亦或是OutBoundHandler。 37 | 38 | 这样的改动,优点显而易见。简化了层次结构,降低了框架的复杂度。同时功能上却没有什么变化。易于使用了解。 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /netty-client/netty-client.iml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /netty-file-server/src/main/java/com/lwhtarena/netty/netty4/util/FileTransferProperties.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.netty4.util; 2 | 3 | import org.springframework.core.io.FileSystemResourceLoader; 4 | import org.springframework.core.io.Resource; 5 | import org.springframework.util.StringUtils; 6 | 7 | import java.io.IOException; 8 | import java.util.Properties; 9 | 10 | /** 11 | * @author: liwh 12 | * @Date: 2016/11/17. 13 | * @Description: 14 | */ 15 | public class FileTransferProperties { 16 | private static Properties pro = new Properties(); 17 | 18 | public static void load(String path) { 19 | FileSystemResourceLoader fileSystemResourceLoader = new FileSystemResourceLoader(); 20 | Resource resource = fileSystemResourceLoader.getResource(path); 21 | try { 22 | pro.load(resource.getInputStream()); 23 | } catch (IOException e) { 24 | e.printStackTrace(); 25 | } 26 | } 27 | 28 | public static String getString(String key, String defaultValue) { 29 | String value = (String) pro.get(key); 30 | if (StringUtils.isEmpty(value)) { 31 | return defaultValue; 32 | } 33 | return value; 34 | } 35 | 36 | public static String getString(String key) { 37 | String value = (String) pro.get(key); 38 | return value; 39 | } 40 | 41 | public static int getInt(String key, int defaultValue) { 42 | Object value = pro.get(key); 43 | if (StringUtils.isEmpty(value)) { 44 | return defaultValue; 45 | } 46 | return Integer.parseInt(value.toString()); 47 | } 48 | 49 | public static boolean getBoolean(String key, boolean defaultValue) { 50 | Object value = (Boolean) pro.get(key); 51 | if (StringUtils.isEmpty(value)) { 52 | return defaultValue; 53 | } 54 | return Boolean.parseBoolean(value.toString()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/tutorial03/util/FileTransferProperties.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial03.util; 2 | 3 | import org.springframework.core.io.FileSystemResourceLoader; 4 | import org.springframework.core.io.Resource; 5 | import org.springframework.util.StringUtils; 6 | 7 | import java.io.IOException; 8 | import java.util.Properties; 9 | 10 | /** 11 | * @author: liwh 12 | * @Date: 2016/11/17. 13 | * @Description: 14 | */ 15 | public class FileTransferProperties { 16 | private static Properties pro = new Properties(); 17 | 18 | public static void load(String path) { 19 | FileSystemResourceLoader fileSystemResourceLoader = new FileSystemResourceLoader(); 20 | Resource resource = fileSystemResourceLoader.getResource(path); 21 | try { 22 | pro.load(resource.getInputStream()); 23 | } catch (IOException e) { 24 | e.printStackTrace(); 25 | } 26 | } 27 | 28 | public static String getString(String key, String defaultValue) { 29 | String value = (String) pro.get(key); 30 | if (StringUtils.isEmpty(value)) { 31 | return defaultValue; 32 | } 33 | return value; 34 | } 35 | 36 | public static String getString(String key) { 37 | String value = (String) pro.get(key); 38 | return value; 39 | } 40 | 41 | public static int getInt(String key, int defaultValue) { 42 | Object value = pro.get(key); 43 | if (StringUtils.isEmpty(value)) { 44 | return defaultValue; 45 | } 46 | return Integer.parseInt(value.toString()); 47 | } 48 | 49 | public static boolean getBoolean(String key, boolean defaultValue) { 50 | Object value = (Boolean) pro.get(key); 51 | if (StringUtils.isEmpty(value)) { 52 | return defaultValue; 53 | } 54 | return Boolean.parseBoolean(value.toString()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial04/ClientHeartbeatHandler.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial04; 2 | 3 | import com.lwhtarena.netty.tutorial04.common.PacketProto; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelInboundHandlerAdapter; 6 | import io.netty.handler.timeout.IdleStateEvent; 7 | 8 | import static com.lwhtarena.netty.tutorial04.common.PacketProto.Packet.newBuilder; 9 | 10 | 11 | /** 12 | * Created by Yohann on 2016/11/9. 13 | */ 14 | public class ClientHeartbeatHandler extends ChannelInboundHandlerAdapter { 15 | @Override 16 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 17 | System.out.println("--- Server is active ---"); 18 | } 19 | 20 | @Override 21 | public void channelInactive(ChannelHandlerContext ctx) throws Exception { 22 | System.out.println("--- Server is inactive ---"); 23 | 24 | // 10s 之后尝试重新连接服务器 25 | System.out.println("10s 之后尝试重新连接服务器..."); 26 | Thread.sleep(10 * 1000); 27 | Client.doConnect(); 28 | } 29 | 30 | @Override 31 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 32 | if (evt instanceof IdleStateEvent) { 33 | // 不管是读事件空闲还是写事件空闲都向服务器发送心跳包 34 | sendHeartbeatPacket(ctx); 35 | } 36 | } 37 | 38 | @Override 39 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 40 | System.out.println("连接出现异常"); 41 | } 42 | 43 | /** 44 | * 发送心跳包 45 | * 46 | * @param ctx 47 | */ 48 | private void sendHeartbeatPacket(ChannelHandlerContext ctx) { 49 | PacketProto.Packet.Builder builder = newBuilder(); 50 | builder.setPacketType(PacketProto.Packet.PacketType.HEARTBEAT); 51 | PacketProto.Packet packet = builder.build(); 52 | ctx.writeAndFlush(packet); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /netty-file-server/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.lwhtarena.netty 6 | netty-file-server 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | netty-file-server 11 | http://maven.apache.org 12 | 13 | 14 | UTF-8 15 | 16 | 17 | 18 | 19 | junit 20 | junit 21 | 3.8.1 22 | test 23 | 24 | 25 | 26 | 27 | io.netty 28 | netty-all 29 | 4.0.23.Final 30 | 31 | 32 | 33 | org.springframework 34 | spring-core 35 | 3.2.3.RELEASE 36 | 37 | 38 | 39 | org.mortbay.jetty 40 | servlet-api-2.5 41 | 6.1.14 42 | 43 | 44 | 45 | org.slf4j 46 | slf4j-api 47 | 1.6.6 48 | 49 | 50 | 51 | org.slf4j 52 | slf4j-log4j12 53 | 1.6.6 54 | 55 | 56 | 57 | com.alibaba 58 | fastjson 59 | 1.2.2 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial05/module/QueryMsg.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial05.module; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.lwhtarena.netty.tutorial05.module.enums.MsgType; 5 | import com.lwhtarena.netty.tutorial05.module.enums.QueryType; 6 | import com.lwhtarena.netty.tutorial05.server.ServerTools; 7 | 8 | public class QueryMsg extends BaseMsg{ 9 | 10 | private static final long serialVersionUID = -4161243660761537875L; 11 | //查询ID 12 | private String queryId; 13 | /** 设备Id */ 14 | private String equId; 15 | /** 查询类型 */ 16 | private QueryType queryType; 17 | /** 查询参数 */ 18 | private String params; 19 | /** 查询结果 */ 20 | private JSONObject resultData; 21 | /** 22 | * 查询指定信息 23 | * @param clientId 客户端ID 24 | * @param equId 查询ID等 25 | * @param queryType 查询类型 26 | */ 27 | public QueryMsg(String clientId, String equId, QueryType queryType, String params) { 28 | super(clientId); 29 | this.setType(MsgType.QUERY); 30 | this.queryId = ServerTools.get32UUID(); 31 | this.equId = equId; 32 | this.queryType = queryType; 33 | this.params = params; 34 | } 35 | 36 | 37 | public String getQueryId() { 38 | return queryId; 39 | } 40 | public void setQueryId(String queryId) { 41 | this.queryId = queryId; 42 | } 43 | 44 | public String getEquId() { 45 | return equId; 46 | } 47 | 48 | public void setEquId(String equId) { 49 | this.equId = equId; 50 | } 51 | 52 | public String getParams() { 53 | return params; 54 | } 55 | 56 | public void setParams(String params) { 57 | this.params = params; 58 | } 59 | 60 | public JSONObject getResultData() { 61 | return resultData; 62 | } 63 | 64 | public void setResultData(JSONObject resultData) { 65 | this.resultData = resultData; 66 | } 67 | public QueryType getQueryType() { 68 | return queryType; 69 | } 70 | public void setQueryType(QueryType queryType) { 71 | this.queryType = queryType; 72 | } 73 | 74 | 75 | } 76 | -------------------------------------------------------------------------------- /netty-server/netty-server.iml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /nettyy-demo01/src/main/java/com/lwhtarena/netty/netty4/model/ResponseFile.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.netty4.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author: liwh 7 | * @Date: 2016/11/17. 8 | * @Description:响应文件 9 | */ 10 | public class ResponseFile implements Serializable{ 11 | 12 | /** 13 | * 开始 读取点 14 | */ 15 | private long start; 16 | /** 17 | * 文件的 MD5值 18 | */ 19 | private String file_md5; 20 | /** 21 | * 文件下载地址 22 | */ 23 | private String file_url; 24 | /** 25 | * 上传是否结束 26 | */ 27 | private boolean end; 28 | /** 29 | * 进度 30 | */ 31 | private int progress ; 32 | 33 | 34 | public ResponseFile() { 35 | } 36 | 37 | public long getStart() { 38 | return start; 39 | } 40 | 41 | public void setStart(long start) { 42 | this.start = start; 43 | } 44 | 45 | public String getFile_md5() { 46 | return file_md5; 47 | } 48 | 49 | public void setFile_md5(String file_md5) { 50 | this.file_md5 = file_md5; 51 | } 52 | 53 | public String getFile_url() { 54 | return file_url; 55 | } 56 | 57 | public void setFile_url(String file_url) { 58 | this.file_url = file_url; 59 | } 60 | 61 | public boolean isEnd() { 62 | return end; 63 | } 64 | 65 | public void setEnd(boolean end) { 66 | this.end = end; 67 | } 68 | 69 | public int getProgress() { 70 | return progress; 71 | } 72 | 73 | public void setProgress(int progress) { 74 | this.progress = progress; 75 | } 76 | 77 | @Override 78 | public String toString() { 79 | StringBuilder sb = new StringBuilder(); 80 | sb.append("progress:"); 81 | sb.append(progress); 82 | sb.append("\t\tstart:"); 83 | sb.append(start); 84 | sb.append("\t\tfile_url:"); 85 | sb.append(file_url); 86 | return sb.toString(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial03/model/ResponseFile.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial03.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author: liwh 7 | * @Date: 2016/11/17. 8 | * @Description:响应文件 9 | */ 10 | public class ResponseFile implements Serializable{ 11 | 12 | /** 13 | * 开始 读取点 14 | */ 15 | private long start; 16 | /** 17 | * 文件的 MD5值 18 | */ 19 | private String file_md5; 20 | /** 21 | * 文件下载地址 22 | */ 23 | private String file_url; 24 | /** 25 | * 上传是否结束 26 | */ 27 | private boolean end; 28 | /** 29 | * 进度 30 | */ 31 | private int progress ; 32 | 33 | 34 | public ResponseFile() { 35 | } 36 | 37 | public long getStart() { 38 | return start; 39 | } 40 | 41 | public void setStart(long start) { 42 | this.start = start; 43 | } 44 | 45 | public String getFile_md5() { 46 | return file_md5; 47 | } 48 | 49 | public void setFile_md5(String file_md5) { 50 | this.file_md5 = file_md5; 51 | } 52 | 53 | public String getFile_url() { 54 | return file_url; 55 | } 56 | 57 | public void setFile_url(String file_url) { 58 | this.file_url = file_url; 59 | } 60 | 61 | public boolean isEnd() { 62 | return end; 63 | } 64 | 65 | public void setEnd(boolean end) { 66 | this.end = end; 67 | } 68 | 69 | public int getProgress() { 70 | return progress; 71 | } 72 | 73 | public void setProgress(int progress) { 74 | this.progress = progress; 75 | } 76 | 77 | @Override 78 | public String toString() { 79 | StringBuilder sb = new StringBuilder(); 80 | sb.append("progress:"); 81 | sb.append(progress); 82 | sb.append("\t\tstart:"); 83 | sb.append(start); 84 | sb.append("\t\tfile_url:"); 85 | sb.append(file_url); 86 | return sb.toString(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /netty-file-client/src/main/java/com/lwhtarena/netty/netty4/model/ResponseFile.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.netty4.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author: liwh 7 | * @Date: 2016/11/17. 8 | * @Description:响应文件 9 | */ 10 | public class ResponseFile implements Serializable{ 11 | 12 | /** 13 | * 开始 读取点 14 | */ 15 | private long start; 16 | /** 17 | * 文件的 MD5值 18 | */ 19 | private String file_md5; 20 | /** 21 | * 文件下载地址 22 | */ 23 | private String file_url; 24 | /** 25 | * 上传是否结束 26 | */ 27 | private boolean end; 28 | /** 29 | * 进度 30 | */ 31 | private int progress ; 32 | 33 | 34 | public ResponseFile() { 35 | } 36 | 37 | public long getStart() { 38 | return start; 39 | } 40 | 41 | public void setStart(long start) { 42 | this.start = start; 43 | } 44 | 45 | public String getFile_md5() { 46 | return file_md5; 47 | } 48 | 49 | public void setFile_md5(String file_md5) { 50 | this.file_md5 = file_md5; 51 | } 52 | 53 | public String getFile_url() { 54 | return file_url; 55 | } 56 | 57 | public void setFile_url(String file_url) { 58 | this.file_url = file_url; 59 | } 60 | 61 | public boolean isEnd() { 62 | return end; 63 | } 64 | 65 | public void setEnd(boolean end) { 66 | this.end = end; 67 | } 68 | 69 | public int getProgress() { 70 | return progress; 71 | } 72 | 73 | public void setProgress(int progress) { 74 | this.progress = progress; 75 | } 76 | 77 | @Override 78 | public String toString() { 79 | StringBuilder sb = new StringBuilder(); 80 | sb.append("progress:"); 81 | sb.append(progress); 82 | sb.append("\t\tstart:"); 83 | sb.append(start); 84 | sb.append("\t\tfile_url:"); 85 | sb.append(file_url); 86 | return sb.toString(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/tutorial01/HelloServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial01; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.SimpleChannelInboundHandler; 5 | 6 | import java.net.InetAddress; 7 | 8 | /** 9 | * @author: liwh 10 | * @Date: 2017/1/13. 11 | * @Description:增加自己的逻辑HelloServerHandler 12 | * 自己的Handler我们这里先去继承extends官网推荐的SimpleChannelInboundHandler 。在这里C,由于我们需求里面发送的是字符串。这里的C改写为String。 13 | */ 14 | public class HelloServerHandler extends SimpleChannelInboundHandler { 15 | @Override 16 | protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { 17 | // 收到消息直接打印输出 18 | System.out.println(ctx.channel().remoteAddress() + " Say : " + msg); 19 | 20 | // 返回客户端消息 - 我已经接收到了你的消息 21 | ctx.writeAndFlush("Received your message !\n"); 22 | } 23 | 24 | /** 25 | * 26 | * 覆盖 channelActive 方法 在channel被启用的时候触发 (在建立连接的时候) 27 | * 28 | * channelActive 和 channelInActive 在后面的内容中讲述,这里先不做详细的描述 29 | * */ 30 | @Override 31 | public void channelActive(ChannelHandlerContext ctx) throws Exception { 32 | 33 | System.out.println("RamoteAddress : " + ctx.channel().remoteAddress() + " active !"); 34 | 35 | ctx.writeAndFlush( "Welcome to " + InetAddress.getLocalHost().getHostName() + " service!\n"); 36 | 37 | super.channelActive(ctx); 38 | } 39 | } 40 | 41 | /*** 42 | * 在channelHandlerContent自带一个writeAndFlush方法。方法的作用是写入Buffer并刷入。 43 | * 44 | * 注意:在3.x版本中此处有很大区别。在3.x版本中write()方法是自动flush的。在4.x版本的前面几个版本也是一样的。 45 | * 但是在4.0.9之后修改为WriteAndFlush。普通的write方法将不会发送消息。需要手动在write之后flush()一次 46 | * 47 | * 这里channeActive的意思是当连接活跃(建立)的时候触发.输出消息源的远程地址。并返回欢迎消息。 48 | * 49 | * channelRead0 在这里的作用是类似于3.x版本的messageReceived()。可以当做是每一次收到消息是触发。 50 | * 51 | * 我们在这里的代码是返回客户端一个字符串"Received your message !". 52 | * 53 | * 注意:字符串最后面的"\n"是必须的。因为我们在前面的解码器DelimiterBasedFrameDecoder是一个根据字符串结 54 | * 尾为“\n”来结尾的。假如没有这个字符的话。解码会出现问题。 55 | * 56 | */ 57 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial01/HelloClient.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial01; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.Channel; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioSocketChannel; 8 | 9 | import java.io.BufferedReader; 10 | import java.io.IOException; 11 | import java.io.InputStreamReader; 12 | 13 | /** 14 | * @author: liwh 15 | * @Date: 2017/1/13. 16 | * @Description: 17 | */ 18 | public class HelloClient { 19 | 20 | public static String host = "127.0.0.1"; 21 | public static int port = 7878; 22 | 23 | /** 24 | * @param args 25 | * @throws InterruptedException 26 | * @throws IOException 27 | */ 28 | public static void main(String[] args) throws InterruptedException, IOException { 29 | EventLoopGroup group = new NioEventLoopGroup(); 30 | try { 31 | Bootstrap b = new Bootstrap(); 32 | b.group(group) 33 | .channel(NioSocketChannel.class) 34 | .handler(new HelloClientInitializer()); 35 | 36 | // 连接服务端 37 | Channel ch = b.connect(host, port).sync().channel(); 38 | 39 | // 控制台输入 40 | BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 41 | for (;;) { 42 | String line = in.readLine(); 43 | if (line == null) { 44 | continue; 45 | } 46 | /** 47 | * 向服务端发送在控制台输入的文本 并用"\r\n"结尾 48 | * 之所以用\r\n结尾 是因为我们在handler中添加了 DelimiterBasedFrameDecoder 帧解码。 49 | * 这个解码器是一个根据\n符号位分隔符的解码器。所以每条消息的最后必须加上\n否则无法识别和解码 50 | * */ 51 | ch.writeAndFlush(line + "\r\n"); 52 | } 53 | } finally { 54 | // The connection is closed automatically on shutdown. 55 | group.shutdownGracefully(); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/tutorial02/LargeMappedFiles.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial02; 2 | 3 | import java.io.RandomAccessFile; 4 | import java.nio.MappedByteBuffer; 5 | import java.nio.channels.FileChannel; 6 | 7 | /** 8 | * @author: liwh 9 | * @Date: 2017/1/13. 10 | * @Description:内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件。 11 | * 12 | * 有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问 13 | * 。这种解决办法能大大简化修改文件的代码。 14 | * 15 | * fileChannel.map(FileChannel.MapMode mode, long position, long size)将此通道的文 16 | * 件区域直接映射到内存中。注意,你必须指明,它是从文件的哪个位置开始映射的,映射的范围又有多大; 17 | * 也就是说,它还可以映射一个大文件的某个小片断。 18 | * 19 | * MappedByteBuffer是ByteBuffer的子类,因此它具备了ByteBuffer的所有方法,但新添了force()将 20 | * 缓冲区的内容强制刷新到存储设备中去、load()将存储设备中的数据加载到内存中、isLoaded()位置内存中 21 | * 的数据是否与存储设置上同步。这里只简单地演示了一下put()和get()方法,除此之外,你还可以使用 22 | * asCharBuffer( )之类的方法得到相应基本类型数据的缓冲视图后,可以方便的读写基本类型数据。 23 | */ 24 | public class LargeMappedFiles { 25 | static int length = 0x8000000; // 128 Mb 26 | 27 | public static void main(String[] args) throws Exception { 28 | // 为了以可读可写的方式打开文件,这里使用RandomAccessFile来创建文件。 29 | FileChannel fc = new RandomAccessFile("test.dat", "rw").getChannel(); 30 | //注意,文件通道的可读可写要建立在文件流本身可读写的基础之上 31 | MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_WRITE, 0, length); 32 | //写128M的内容 33 | for (int i = 0; i < length; i++) { 34 | out.put((byte) 'x'); 35 | } 36 | System.out.println("Finished writing"); 37 | //读取文件中间6个字节内容 38 | for (int i = length / 2; i < length / 2 + 6; i++) { 39 | System.out.print((char) out.get(i)); 40 | } 41 | fc.close(); 42 | } 43 | 44 | /*** 45 | * 尽管映射写似乎要用到FileOutputStream,但是映射文件中的所有输出 必须使用RandomAccessFile, 46 | * 但如果只需要读时可以使用FileInputStream,写映射文件时一定要使用随机访问文件,可能写时要读的原因吧。 47 | * 48 | * 该程序创建了一个128Mb的文件,如果一次性读到内存可能导致内存溢出,但这里访问好像只是一瞬间的事, 49 | * 这是因为,真正调入内存的只是其中的一小部分,其余部分则被放在交换文件上。这样你就可以很方便地修改超 50 | * 大型的文件了(最大可以到2 GB)。注意,Java是调用操作系统的"文件映射机制"来提升性能的。 51 | */ 52 | } 53 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/tutorial01/HelloServer.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial01; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.EventLoopGroup; 6 | import io.netty.channel.nio.NioEventLoopGroup; 7 | import io.netty.channel.socket.nio.NioServerSocketChannel; 8 | 9 | /** 10 | * @author: liwh 11 | * @Date: 2017/1/13. 12 | * @Description:创建一个服务 HelloServer 13 | */ 14 | public class HelloServer { 15 | 16 | /** 17 | * 服务端监听的端口地址 18 | */ 19 | private static final int portNumber = 7878; 20 | 21 | /**定义了两个工作线程,一个命名为WorkerGroup,另一个命名为BossGroup。都是实例化NioEventLoopGroup。 22 | * 这一点和3.x版本中基本思路是一致的。Worker线程用于管理线程为Boss线程服务。 23 | * 24 | * @param args 25 | * @throws InterruptedException 26 | */ 27 | public static void main(String[] args) throws InterruptedException { 28 | EventLoopGroup bossGroup = new NioEventLoopGroup(); 29 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 30 | try { 31 | ServerBootstrap b = new ServerBootstrap(); 32 | b.group(bossGroup, workerGroup); 33 | b.channel(NioServerSocketChannel.class); 34 | b.childHandler(new HelloServerInitializer()); 35 | 36 | // 服务器绑定端口监听 37 | ChannelFuture f = b.bind(portNumber).sync(); 38 | // 监听服务器关闭监听 39 | f.channel().closeFuture().sync(); 40 | 41 | // 可以简写为 42 | /* b.bind(portNumber).sync().channel().closeFuture().sync(); */ 43 | } finally { 44 | /** EventLoopGroup,它是4.x版本提出来的一个新概念。类似于3.x版本中的线程。用于管理Channel连接的。 45 | * shutdownGraceFully(),翻译为中文就是优雅的全部关闭. 46 | * 我们可以在DefaultEventExecutorGroup的父类MultithreadEventExecutorGroup中看到它的实现代码。关闭 47 | * 了全部EventExecutor数组child里面子元素。相比于3.x版本这是一个比较重大的改动。开发者可以很轻松的全部关闭, 48 | * 而不需要担心出现内存泄露。 49 | * 50 | */ 51 | bossGroup.shutdownGracefully(); 52 | workerGroup.shutdownGracefully(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /netty-bigFile/src/main/java/com/lwhtarena/netty/file/HttpStaticFileServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package com.lwhtarena.netty.file; 17 | 18 | import io.netty.bootstrap.ServerBootstrap; 19 | import io.netty.channel.EventLoopGroup; 20 | import io.netty.channel.nio.NioEventLoopGroup; 21 | import io.netty.channel.socket.nio.NioServerSocketChannel; 22 | 23 | public class HttpStaticFileServer { 24 | 25 | private final int port; 26 | 27 | public HttpStaticFileServer(int port) { 28 | this.port = port; 29 | } 30 | 31 | public void run() throws Exception { 32 | EventLoopGroup bossGroup = new NioEventLoopGroup(1); 33 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 34 | try { 35 | ServerBootstrap b = new ServerBootstrap(); 36 | b.group(bossGroup, workerGroup) 37 | .channel(NioServerSocketChannel.class) 38 | .childHandler(new HttpStaticFileServerInitializer()); 39 | 40 | b.bind(port).sync().channel().closeFuture().sync(); 41 | } finally { 42 | bossGroup.shutdownGracefully(); 43 | workerGroup.shutdownGracefully(); 44 | } 45 | } 46 | 47 | public static void main(String[] args) throws Exception { 48 | int port; 49 | if (args.length > 0) { 50 | port = Integer.parseInt(args[0]); 51 | } else { 52 | port = 9003; 53 | } 54 | new HttpStaticFileServer(port).run(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /nettyy-demo01/src/main/java/com/lwhtarena/netty/netty4/model/RequestFile.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.netty4.model; 2 | 3 | import java.io.File; 4 | import java.io.Serializable; 5 | 6 | /** 7 | * @author: liwh 8 | * @Date: 2016/11/17. 9 | * @Description:请求文件 10 | */ 11 | public class RequestFile implements Serializable{ 12 | 13 | private File file;// 文件 14 | private String file_name;// 文件名 15 | private long starPos;// 开始位置 16 | private byte[] bytes;// 文件字节数组 17 | private int endPos;// 结尾位置 18 | private String file_md5; //文件的MD5值 19 | private String file_type; //文件类型 20 | private long file_size; //文件总长度 21 | 22 | public RequestFile() { 23 | } 24 | 25 | public File getFile() { 26 | return file; 27 | } 28 | 29 | public void setFile(File file) { 30 | this.file = file; 31 | } 32 | 33 | public String getFile_name() { 34 | return file_name; 35 | } 36 | 37 | public void setFile_name(String file_name) { 38 | this.file_name = file_name; 39 | } 40 | 41 | public long getStarPos() { 42 | return starPos; 43 | } 44 | 45 | public void setStarPos(long starPos) { 46 | this.starPos = starPos; 47 | } 48 | 49 | public byte[] getBytes() { 50 | return bytes; 51 | } 52 | 53 | public void setBytes(byte[] bytes) { 54 | this.bytes = bytes; 55 | } 56 | 57 | public int getEndPos() { 58 | return endPos; 59 | } 60 | 61 | public void setEndPos(int endPos) { 62 | this.endPos = endPos; 63 | } 64 | 65 | public String getFile_md5() { 66 | return file_md5; 67 | } 68 | 69 | public void setFile_md5(String file_md5) { 70 | this.file_md5 = file_md5; 71 | } 72 | 73 | public String getFile_type() { 74 | return file_type; 75 | } 76 | 77 | public void setFile_type(String file_type) { 78 | this.file_type = file_type; 79 | } 80 | 81 | public long getFile_size() { 82 | return file_size; 83 | } 84 | 85 | public void setFile_size(long file_size) { 86 | this.file_size = file_size; 87 | } 88 | 89 | 90 | } 91 | -------------------------------------------------------------------------------- /netty-file-client/src/main/java/com/lwhtarena/netty/netty4/model/RequestFile.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.netty4.model; 2 | 3 | import java.io.File; 4 | import java.io.Serializable; 5 | 6 | /** 7 | * @author: liwh 8 | * @Date: 2016/11/17. 9 | * @Description:请求文件 10 | */ 11 | public class RequestFile implements Serializable{ 12 | 13 | private File file;// 文件 14 | private String file_name;// 文件名 15 | private long starPos;// 开始位置 16 | private byte[] bytes;// 文件字节数组 17 | private int endPos;// 结尾位置 18 | private String file_md5; //文件的MD5值 19 | private String file_type; //文件类型 20 | private long file_size; //文件总长度 21 | 22 | public RequestFile() { 23 | } 24 | 25 | public File getFile() { 26 | return file; 27 | } 28 | 29 | public void setFile(File file) { 30 | this.file = file; 31 | } 32 | 33 | public String getFile_name() { 34 | return file_name; 35 | } 36 | 37 | public void setFile_name(String file_name) { 38 | this.file_name = file_name; 39 | } 40 | 41 | public long getStarPos() { 42 | return starPos; 43 | } 44 | 45 | public void setStarPos(long starPos) { 46 | this.starPos = starPos; 47 | } 48 | 49 | public byte[] getBytes() { 50 | return bytes; 51 | } 52 | 53 | public void setBytes(byte[] bytes) { 54 | this.bytes = bytes; 55 | } 56 | 57 | public int getEndPos() { 58 | return endPos; 59 | } 60 | 61 | public void setEndPos(int endPos) { 62 | this.endPos = endPos; 63 | } 64 | 65 | public String getFile_md5() { 66 | return file_md5; 67 | } 68 | 69 | public void setFile_md5(String file_md5) { 70 | this.file_md5 = file_md5; 71 | } 72 | 73 | public String getFile_type() { 74 | return file_type; 75 | } 76 | 77 | public void setFile_type(String file_type) { 78 | this.file_type = file_type; 79 | } 80 | 81 | public long getFile_size() { 82 | return file_size; 83 | } 84 | 85 | public void setFile_size(long file_size) { 86 | this.file_size = file_size; 87 | } 88 | 89 | 90 | } 91 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial03/model/RequestFile.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial03.model; 2 | 3 | import java.io.File; 4 | import java.io.Serializable; 5 | 6 | /** 7 | * @author: liwh 8 | * @Date: 2016/11/17. 9 | * @Description:请求文件 10 | */ 11 | public class RequestFile implements Serializable{ 12 | 13 | private File file;// 文件 14 | private String file_name;// 文件名 15 | private long starPos;// 开始位置 16 | private byte[] bytes;// 文件字节数组 17 | private int endPos;// 结尾位置 18 | private String file_md5; //文件的MD5值 19 | private String file_type; //文件类型 20 | private long file_size; //文件总长度 21 | 22 | public RequestFile() { 23 | } 24 | 25 | public File getFile() { 26 | return file; 27 | } 28 | 29 | public void setFile(File file) { 30 | this.file = file; 31 | } 32 | 33 | public String getFile_name() { 34 | return file_name; 35 | } 36 | 37 | public void setFile_name(String file_name) { 38 | this.file_name = file_name; 39 | } 40 | 41 | public long getStarPos() { 42 | return starPos; 43 | } 44 | 45 | public void setStarPos(long starPos) { 46 | this.starPos = starPos; 47 | } 48 | 49 | public byte[] getBytes() { 50 | return bytes; 51 | } 52 | 53 | public void setBytes(byte[] bytes) { 54 | this.bytes = bytes; 55 | } 56 | 57 | public int getEndPos() { 58 | return endPos; 59 | } 60 | 61 | public void setEndPos(int endPos) { 62 | this.endPos = endPos; 63 | } 64 | 65 | public String getFile_md5() { 66 | return file_md5; 67 | } 68 | 69 | public void setFile_md5(String file_md5) { 70 | this.file_md5 = file_md5; 71 | } 72 | 73 | public String getFile_type() { 74 | return file_type; 75 | } 76 | 77 | public void setFile_type(String file_type) { 78 | this.file_type = file_type; 79 | } 80 | 81 | public long getFile_size() { 82 | return file_size; 83 | } 84 | 85 | public void setFile_size(long file_size) { 86 | this.file_size = file_size; 87 | } 88 | 89 | 90 | } 91 | -------------------------------------------------------------------------------- /netty-bigFile/src/main/java/com/lwhtarena/netty/file/HttpStaticFileServerInitializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package com.lwhtarena.netty.file; 17 | 18 | import io.netty.channel.ChannelInitializer; 19 | import io.netty.channel.ChannelPipeline; 20 | import io.netty.channel.socket.SocketChannel; 21 | import io.netty.handler.codec.http.HttpObjectAggregator; 22 | import io.netty.handler.codec.http.HttpRequestDecoder; 23 | import io.netty.handler.codec.http.HttpResponseEncoder; 24 | import io.netty.handler.stream.ChunkedWriteHandler; 25 | 26 | public class HttpStaticFileServerInitializer extends ChannelInitializer { 27 | @Override 28 | public void initChannel(SocketChannel ch) throws Exception { 29 | // Create a default pipeline implementation. 30 | ChannelPipeline pipeline = ch.pipeline(); 31 | 32 | // Uncomment the following line if you want HTTPS 33 | //SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine(); 34 | //engine.setUseClientMode(false); 35 | //pipeline.addLast("ssl", new SslHandler(engine)); 36 | 37 | pipeline.addLast("encoder", new HttpResponseEncoder()); 38 | pipeline.addLast("decoder", new HttpRequestDecoder()); 39 | pipeline.addLast("aggregator", new HttpObjectAggregator(65536)); 40 | pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); 41 | 42 | pipeline.addLast("handler", new HttpStaticFileServerHandler(true)); // Specify false if SSL. 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/demo02/ObjectServer.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.demo02; 2 | 3 | import io.netty.bootstrap.ServerBootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelInitializer; 6 | import io.netty.channel.ChannelOption; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioServerSocketChannel; 11 | import io.netty.handler.codec.serialization.ClassResolvers; 12 | import io.netty.handler.codec.serialization.ObjectDecoder; 13 | import io.netty.handler.codec.serialization.ObjectEncoder; 14 | 15 | /** 16 | * @author: liwh 17 | * @Date: 2017/1/12. 18 | * @Description: 19 | */ 20 | public class ObjectServer { 21 | public void run() throws InterruptedException { 22 | EventLoopGroup bossGroup = new NioEventLoopGroup(); 23 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 24 | try { 25 | ServerBootstrap b = new ServerBootstrap(); 26 | b.group(bossGroup, workerGroup) 27 | .channel(NioServerSocketChannel.class) 28 | .childHandler(new ChannelInitializer() { 29 | @Override 30 | protected void initChannel(SocketChannel ch) throws Exception { 31 | ch.pipeline().addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(this.getClass().getClassLoader())), new ObjectEncoder(), new ObjectServerHandler()); 32 | } 33 | }) 34 | .option(ChannelOption.SO_BACKLOG, 128) 35 | .childOption(ChannelOption.SO_KEEPALIVE, true); 36 | ChannelFuture f = b.bind(7777).sync(); 37 | System.out.println("server started."); 38 | f.channel().closeFuture().sync(); 39 | } finally { 40 | workerGroup.shutdownGracefully(); 41 | bossGroup.shutdownGracefully(); 42 | } 43 | } 44 | 45 | public static void main(String[] args) throws Exception { 46 | new ObjectServer().run(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /nettyy-demo01/src/main/java/com/lwhtarena/netty/基本案例01/echo/client/EchoClientHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 The Netty Project 3 | * 4 | * The Netty Project licenses this file to you under the Apache License, 5 | * version 2.0 (the "License"); you may not use this file except in compliance 6 | * with the License. You may obtain a copy of the License at: 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 | * License for the specific language governing permissions and limitations 14 | * under the License. 15 | */ 16 | package com.lwhtarena.netty.基本案例01.echo.client; 17 | 18 | import io.netty.buffer.ByteBuf; 19 | import io.netty.buffer.Unpooled; 20 | import io.netty.channel.ChannelHandlerContext; 21 | import io.netty.channel.ChannelInboundHandlerAdapter; 22 | 23 | /** 24 | * Handler implementation for the echo client. It initiates the ping-pong 25 | * traffic between the echo client and server by sending the first message to 26 | * the server. 27 | */ 28 | public class EchoClientHandler extends ChannelInboundHandlerAdapter { 29 | 30 | private final ByteBuf firstMessage; 31 | 32 | /** 33 | * Creates a client-side handler. 34 | */ 35 | public EchoClientHandler() { 36 | firstMessage = Unpooled.buffer(EchoClient.SIZE); 37 | for (int i = 0; i < firstMessage.capacity(); i ++) { 38 | firstMessage.writeByte((byte) i); 39 | } 40 | } 41 | 42 | @Override 43 | public void channelActive(ChannelHandlerContext ctx) { 44 | ctx.writeAndFlush(firstMessage); 45 | } 46 | 47 | @Override 48 | public void channelRead(ChannelHandlerContext ctx, Object msg) { 49 | ctx.write(msg); 50 | } 51 | 52 | @Override 53 | public void channelReadComplete(ChannelHandlerContext ctx) { 54 | ctx.flush(); 55 | } 56 | 57 | @Override 58 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 59 | // Close the connection when an exception is raised. 60 | cause.printStackTrace(); 61 | ctx.close(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/tutorial04/Server.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial04; 2 | 3 | import com.lwhtarena.netty.tutorial04.common.PacketProto; 4 | import io.netty.bootstrap.ServerBootstrap; 5 | import io.netty.channel.Channel; 6 | import io.netty.channel.ChannelInitializer; 7 | import io.netty.channel.ChannelPipeline; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioServerSocketChannel; 11 | import io.netty.handler.codec.protobuf.ProtobufDecoder; 12 | import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; 13 | import io.netty.handler.timeout.IdleStateHandler; 14 | 15 | /** 16 | * Created by Yohann on 2016/11/9. 17 | */ 18 | public class Server { 19 | public static void main(String[] args) { 20 | NioEventLoopGroup acceptorGroup = new NioEventLoopGroup(1); 21 | NioEventLoopGroup workerGroup = new NioEventLoopGroup(); 22 | try { 23 | ServerBootstrap bootstrap = new ServerBootstrap(); 24 | bootstrap 25 | .group(acceptorGroup, workerGroup) 26 | .channel(NioServerSocketChannel.class) 27 | .childHandler(new ChannelInitializer() { 28 | @Override 29 | protected void initChannel(SocketChannel ch) throws Exception { 30 | ChannelPipeline pipeline = ch.pipeline(); 31 | pipeline.addLast(new ProtobufVarint32FrameDecoder()); 32 | pipeline.addLast(new ProtobufDecoder(PacketProto.Packet.getDefaultInstance())); 33 | pipeline.addLast(new IdleStateHandler(6, 0, 0)); 34 | pipeline.addLast(new ServerHeartbeatHandler()); 35 | } 36 | }); 37 | Channel ch = bootstrap.bind(20000).sync().channel(); 38 | System.out.println("Server has started..."); 39 | ch.closeFuture().sync(); 40 | } catch (InterruptedException e) { 41 | e.printStackTrace(); 42 | } finally { 43 | acceptorGroup.shutdownGracefully(); 44 | workerGroup.shutdownGracefully(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial02/thread02/ReadThread.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial02.thread02; 2 | 3 | /** 4 | * @author: liwh 5 | * @Date: 2017/2/5. 6 | * @Description:java 线程的开始、暂停、继续 7 | * 8 | * 一个需求:通过线程读取文件内容,并且可以控制线程的开始、暂停、继续,来控制读文件。在此记录下。 9 | 10 | 直接在主线程中,通过wait、notify、notifyAll去控制读文件的线程(子线程),报错:java.lang.IllegalMonitorStateException。 11 | 12 | 需要注意的几个问题: 13 | 14 | 1.任何一个时刻,对象的控制权(monitor)只能被一个线程拥有。 15 | 16 | 2.无论是执行对象的wait、notify还是notifyAll方法,必须保证当前运行的线程取得了该对象的控制权(monitor)。 17 | 18 | 3.如果在没有控制权的线程里执行对象的以上三种方法,就会报错java.lang.IllegalMonitorStateException。 19 | 20 | 4.JVM基于多线程,默认情况下不能保证运行时线程的时序性。 21 | 22 | 线程取得控制权的3种方法: 23 | 24 | 1.执行对象的某个同步实例方法。 25 | 26 | 2.执行对象对应类的同步静态方法。 27 | 28 | 3.执行对该对象加同步锁的同步块。 29 | 30 | 这里将开始、暂停、继续封装在线程类中,直接调用该实例的方法就行。 31 | * 32 | */ 33 | public class ReadThread implements Runnable{ 34 | 35 | public Thread t; 36 | private String threadName; 37 | boolean suspended =false; 38 | 39 | public ReadThread(String threadName) { 40 | this.threadName = threadName; 41 | System.out.println("创建线程... : "+threadName); 42 | } 43 | 44 | @Override 45 | public void run() { 46 | for (int i=100;i>0;i--){ 47 | System.out.println("线程: "+threadName+" , "+i); 48 | try { 49 | Thread.sleep(300); 50 | synchronized (this){ 51 | while (suspended){ 52 | wait(); 53 | } 54 | } 55 | } catch (InterruptedException e) { 56 | System.out.println("Thread " + threadName + " interrupted."); 57 | e.printStackTrace(); 58 | } 59 | } 60 | System.out.println("Thread " + threadName + " exiting."); 61 | } 62 | 63 | /** 64 | * 开始 65 | */ 66 | public void start(){ 67 | System.out.println("开始: "+threadName); 68 | if(t==null){ 69 | t =new Thread(this,threadName); 70 | t.start(); 71 | } 72 | } 73 | 74 | 75 | /** 76 | * 暂停 77 | */ 78 | void suspend(){ 79 | suspended =true; 80 | } 81 | 82 | /** 83 | * 继续 84 | */ 85 | synchronized void resume(){ 86 | suspended =false; 87 | notify(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /netty-file-server/src/main/java/com/lwhtarena/netty/netty4/server/SecureServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.netty4.server; 2 | 3 | import com.lwhtarena.netty.netty4.model.SecureModel; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelInboundHandlerAdapter; 6 | import io.netty.channel.group.ChannelGroup; 7 | import io.netty.channel.group.DefaultChannelGroup; 8 | import io.netty.util.concurrent.GlobalEventExecutor; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | /** 13 | * @author: liwh 14 | * @Date: 2016/11/17. 15 | * @Description: 16 | */ 17 | public class SecureServerHandler extends ChannelInboundHandlerAdapter { 18 | private static final Logger log = LoggerFactory.getLogger(SecureServerHandler.class); 19 | static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); 20 | 21 | @Override 22 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 23 | if( msg instanceof SecureModel){ 24 | SecureModel secureModel = (SecureModel)msg; 25 | if(secureModel.getToken() != null ){ 26 | //TODO 验证 token 是否存在,并且token对应的 ip和 ctx里面来源ip是否一致 27 | if(true){ 28 | log.info("NEW TCP >" + ctx.channel().remoteAddress()); 29 | log.info("now connection count >" +channels.size()); 30 | 31 | channels.add(ctx.channel()); 32 | secureModel.setAutoSuccess(true); 33 | ctx.writeAndFlush(secureModel); 34 | return ; 35 | } 36 | } 37 | secureModel.setAutoSuccess(false); 38 | ctx.writeAndFlush(secureModel); 39 | ctx.close(); 40 | }else{ 41 | if( !channels.contains(ctx.channel()) ) { 42 | SecureModel secureModel = new SecureModel(); 43 | secureModel.setAutoSuccess(false); 44 | ctx.writeAndFlush(secureModel); 45 | ctx.close(); 46 | } else { 47 | ctx.fireChannelRead(msg); //继续执行 48 | } 49 | } 50 | } 51 | 52 | 53 | @Override 54 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 55 | cause.printStackTrace(); 56 | ctx.close(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/tutorial03/server/SecureServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial03.server; 2 | 3 | import com.lwhtarena.netty.tutorial03.model.SecureModel; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelInboundHandlerAdapter; 6 | import io.netty.channel.group.ChannelGroup; 7 | import io.netty.channel.group.DefaultChannelGroup; 8 | import io.netty.util.concurrent.GlobalEventExecutor; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | /** 13 | * @author: liwh 14 | * @Date: 2016/11/17. 15 | * @Description: 16 | */ 17 | public class SecureServerHandler extends ChannelInboundHandlerAdapter { 18 | private static final Logger log = LoggerFactory.getLogger(SecureServerHandler.class); 19 | static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); 20 | 21 | @Override 22 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 23 | if( msg instanceof SecureModel){ 24 | SecureModel secureModel = (SecureModel)msg; 25 | if(secureModel.getToken() != null ){ 26 | //TODO 验证 token 是否存在,并且token对应的 ip和 ctx里面来源ip是否一致 27 | if(true){ 28 | log.info("NEW TCP >" + ctx.channel().remoteAddress()); 29 | log.info("now connection count >" +channels.size()); 30 | 31 | channels.add(ctx.channel()); 32 | secureModel.setAutoSuccess(true); 33 | ctx.writeAndFlush(secureModel); 34 | return ; 35 | } 36 | } 37 | secureModel.setAutoSuccess(false); 38 | ctx.writeAndFlush(secureModel); 39 | ctx.close(); 40 | }else{ 41 | if( !channels.contains(ctx.channel()) ) { 42 | SecureModel secureModel = new SecureModel(); 43 | secureModel.setAutoSuccess(false); 44 | ctx.writeAndFlush(secureModel); 45 | ctx.close(); 46 | } else { 47 | ctx.fireChannelRead(msg); //继续执行 48 | } 49 | } 50 | } 51 | 52 | 53 | @Override 54 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { 55 | cause.printStackTrace(); 56 | ctx.close(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial06/DownFileInfoBean.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial06; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * @author: liwh 7 | * @Date: 2017/2/6. 8 | * @Description: 9 | */ 10 | public class DownFileInfoBean { 11 | private String sSiteURL; // 文件的下载地址 12 | private String sFilePath; // 保存文件的路径 13 | private String sFileName; // 保存文件的名字 14 | private int nSplitter; // 文件分成几段,默认是5段 15 | private boolean fileflag; // 如果为FALSE则是本地下载,为TRUE则URL下载 16 | private File downfile; 17 | 18 | public File getDownfile() { 19 | return downfile; 20 | } 21 | 22 | public void setDownfile(File downfile) { 23 | this.downfile = downfile; 24 | } 25 | 26 | public boolean getFileflag() { 27 | return fileflag; 28 | } 29 | 30 | public void setFileflag(boolean fileflag) { 31 | this.fileflag = fileflag; 32 | } 33 | 34 | /** 35 | * 默认初始化 36 | */ 37 | public DownFileInfoBean() { 38 | // default 5 39 | this("", "", "", 5,false,null); 40 | } 41 | 42 | /** 43 | * 下载文件信息初始化 44 | * @param sURL 下载的链接地址 45 | * @param sPath 上传的保存路径 46 | * @param sName 上传保存的文件名 47 | * @param nSpiltter 文件分段个数 48 | * @param fileflag 是本地文件上传下载还是链接上传下载的标志 49 | * @param downfile 本地下载文件(FILE) 50 | */ 51 | public DownFileInfoBean(String sURL, String sPath, String sName, int nSpiltter,boolean fileflag,File downfile) { 52 | sSiteURL = sURL; 53 | sFilePath = sPath; 54 | sFileName = sName; 55 | this.nSplitter = nSpiltter; 56 | this.fileflag = fileflag; 57 | this.downfile = downfile; 58 | } 59 | 60 | public String getSSiteURL() { 61 | return sSiteURL; 62 | } 63 | 64 | public void setSSiteURL(String value) { 65 | sSiteURL = value; 66 | } 67 | 68 | public String getSFilePath() { 69 | return sFilePath; 70 | } 71 | 72 | public void setSFilePath(String value) { 73 | sFilePath = value; 74 | } 75 | 76 | public String getSFileName() { 77 | return sFileName; 78 | } 79 | 80 | public void setSFileName(String value) { 81 | sFileName = value; 82 | } 83 | 84 | public int getNSplitter() { 85 | return nSplitter; 86 | } 87 | 88 | public void setNSplitter(int nCount) { 89 | nSplitter = nCount; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /netty-bigFile/src/main/java/com/lwhtarena/netty/bigFile/intermediary/IntermediaryClient.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.bigFile.intermediary; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioSocketChannel; 9 | import io.netty.handler.codec.http.DefaultFullHttpRequest; 10 | import io.netty.handler.codec.http.HttpHeaders; 11 | import io.netty.handler.codec.http.HttpMethod; 12 | import io.netty.handler.codec.http.HttpVersion; 13 | 14 | import java.net.URI; 15 | 16 | /** 17 | * @author: liwh 18 | * @Date: 2017/2/6. 19 | * @Description:中介客户端 20 | */ 21 | public class IntermediaryClient { 22 | 23 | /** 24 | * 25 | * 向互联网下载输入完整路径 26 | * @param host 目的主机 ip 或域名 27 | * @param port 目标主机端口 28 | * @param url 文件路径 29 | * @param local 本地存储路径 ===文件名 30 | */ 31 | public void connect(String host,int port,String url,String local) throws Exception{ 32 | 33 | EventLoopGroup workerGroup =new NioEventLoopGroup(); 34 | 35 | try { 36 | Bootstrap b =new Bootstrap(); 37 | 38 | b.group(workerGroup); 39 | b.channel(NioSocketChannel.class); 40 | b.option(ChannelOption.SO_KEEPALIVE,true); 41 | b.handler(new IntermediaryChannelHandler()); 42 | 43 | /*--========== 启动客户端 ==========--*/ 44 | ChannelFuture f =b.connect(host,port).sync(); 45 | URI uri = new URI(url); 46 | /**DefaultFullHttpRequest --模拟浏览器请求,http的版本|http的请求方式|请求url**/ 47 | DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri.toASCIIString()); 48 | 49 | /*--======== 构建 http 请求 =========--*/ 50 | request.headers().set(HttpHeaders.Names.HOST, host); 51 | request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE); 52 | request.headers().set(HttpHeaders.Names.CONTENT_LENGTH, request.content().readableBytes()); 53 | 54 | /*--======== 发送 http 请求 =========--*/ 55 | f.channel().write(request); 56 | f.channel().flush(); 57 | f.channel().closeFuture().sync(); 58 | }finally { 59 | workerGroup.shutdownGracefully();//优雅退出 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/demo01/HttpServer.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.demo01; 2 | 3 | import org.apache.commons.logging.Log; 4 | import org.apache.commons.logging.LogFactory; 5 | 6 | import io.netty.bootstrap.ServerBootstrap; 7 | import io.netty.channel.ChannelFuture; 8 | import io.netty.channel.ChannelInitializer; 9 | import io.netty.channel.ChannelOption; 10 | import io.netty.channel.EventLoopGroup; 11 | import io.netty.channel.nio.NioEventLoopGroup; 12 | import io.netty.channel.socket.SocketChannel; 13 | import io.netty.channel.socket.nio.NioServerSocketChannel; 14 | import io.netty.handler.codec.http.HttpRequestDecoder; 15 | import io.netty.handler.codec.http.HttpResponseEncoder; 16 | 17 | /** 18 | * @author: liwh 19 | * @Date: 2017/1/12. 20 | * @Description:http server 21 | */ 22 | public class HttpServer { 23 | 24 | private static Log log = LogFactory.getLog(HttpServer.class); 25 | 26 | public void start(int port) throws Exception { 27 | EventLoopGroup bossGroup = new NioEventLoopGroup(); 28 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 29 | try { 30 | ServerBootstrap b = new ServerBootstrap(); 31 | b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) 32 | .childHandler(new ChannelInitializer() { 33 | @Override 34 | public void initChannel(SocketChannel ch) throws Exception { 35 | // server端发送的是httpResponse,所以要使用HttpResponseEncoder进行编码 36 | ch.pipeline().addLast(new HttpResponseEncoder()); 37 | // server端接收到的是httpRequest,所以要使用HttpRequestDecoder进行解码 38 | ch.pipeline().addLast(new HttpRequestDecoder()); 39 | ch.pipeline().addLast(new HttpServerInboundHandler()); 40 | } 41 | }).option(ChannelOption.SO_BACKLOG, 128) 42 | .childOption(ChannelOption.SO_KEEPALIVE, true); 43 | 44 | ChannelFuture f = b.bind(port).sync(); 45 | 46 | f.channel().closeFuture().sync(); 47 | } finally { 48 | workerGroup.shutdownGracefully(); 49 | bossGroup.shutdownGracefully(); 50 | } 51 | } 52 | 53 | public static void main(String[] args) throws Exception { 54 | HttpServer server = new HttpServer(); 55 | log.info("Http Server listening on 8844 ..."); 56 | server.start(8844); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /netty-client/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.lwhtarena.netty 6 | netty-client 7 | 1.0-SNAPSHOT 8 | 9 | 10 | 11 | org.apache.maven.plugins 12 | maven-compiler-plugin 13 | 14 | 1.8 15 | 1.8 16 | 17 | 18 | 19 | 20 | jar 21 | 22 | netty-client 23 | http://maven.apache.org 24 | 25 | 26 | UTF-8 27 | 28 | 29 | 30 | 31 | junit 32 | junit 33 | 3.8.1 34 | test 35 | 36 | 37 | 38 | 39 | io.netty 40 | netty-all 41 | 4.1.6.Final 42 | compile 43 | 44 | 45 | 46 | org.slf4j 47 | slf4j-api 48 | 1.6.6 49 | 50 | 51 | 52 | com.alibaba 53 | fastjson 54 | 1.2.2 55 | 56 | 57 | org.jboss.netty 58 | netty 59 | 3.2.1.Final 60 | 61 | 62 | com.google.protobuf 63 | protobuf-java 64 | 3.1.0 65 | 66 | 67 | org.apache.httpcomponents 68 | httpclient 69 | 4.5.2 70 | 71 | 72 | junit 73 | junit 74 | 4.12 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/tutorial02/TestRandomAccessFile.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial02; 2 | 3 | /** 4 | * @author: liwh 5 | * @Date: 2017/1/13. 6 | * @Description: 7 | * 利用RandomAccessFile实现文件的多线程下载,即多线程下载一 8 | * 个文件时,将文件分成几块,每块用不同的线程进行下载。 9 | * 10 | * 下面是一个利用多线程在写文件时的例子,其中预先分配文件所需要的空间, 11 | * 然后在所分配的空间中进行分块,然后写入: 12 | */ 13 | 14 | 15 | import java.io.FileNotFoundException; 16 | import java.io.IOException; 17 | import java.io.RandomAccessFile; 18 | 19 | /** 20 | * 测试利用多线程进行文件的写操作 21 | */ 22 | public class TestRandomAccessFile { 23 | 24 | // 利用线程在文件的指定位置写入指定数据 25 | static class FileWriteThread extends Thread{ 26 | private int skip; 27 | private byte[] content; 28 | 29 | public FileWriteThread(int skip,byte[] content){ 30 | this.skip = skip; 31 | this.content = content; 32 | } 33 | 34 | public void run(){ 35 | RandomAccessFile raf = null; 36 | try { 37 | raf = new RandomAccessFile("D://abc.txt", "rw"); 38 | raf.seek(skip); 39 | raf.write(content); 40 | } catch (FileNotFoundException e) { 41 | e.printStackTrace(); 42 | } catch (IOException e) { 43 | // TODO Auto-generated catch block 44 | e.printStackTrace(); 45 | } finally { 46 | try { 47 | raf.close(); 48 | } catch (Exception e) { 49 | } 50 | } 51 | } 52 | } 53 | 54 | public static void main(String[] args) { 55 | 56 | // 预分配文件所占的磁盘空间,磁盘中会创建一个指定大小的文件 57 | RandomAccessFile raf = null; 58 | try { 59 | raf = new RandomAccessFile("D://abc.txt", "rw"); 60 | raf.setLength(1024*1024); // 预分配 1M 的文件空间 61 | raf.close(); 62 | } catch (IOException e) { 63 | e.printStackTrace(); 64 | } 65 | 66 | // 所要写入的文件内容 67 | String s1 = "第一个字符串"; 68 | String s2 = "第二个字符串"; 69 | String s3 = "第三个字符串"; 70 | String s4 = "第四个字符串"; 71 | String s5 = "第五个字符串"; 72 | 73 | // 利用多线程同时写入一个文件 74 | new FileWriteThread(1024*1,s1.getBytes()).start(); // 从文件的1024字节之后开始写入数据 75 | new FileWriteThread(1024*2,s2.getBytes()).start(); // 从文件的2048字节之后开始写入数据 76 | new FileWriteThread(1024*3,s3.getBytes()).start(); // 从文件的3072字节之后开始写入数据 77 | new FileWriteThread(1024*4,s4.getBytes()).start(); // 从文件的4096字节之后开始写入数据 78 | new FileWriteThread(1024*5,s5.getBytes()).start(); // 从文件的5120字节之后开始写入数据 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /netty-bigFile/src/main/java/com/lwhtarena/netty/bigFile/intermediary/OptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.bigFile.intermediary; 2 | 3 | import io.netty.bootstrap.Bootstrap; 4 | import io.netty.channel.ChannelFuture; 5 | import io.netty.channel.ChannelOption; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import io.netty.channel.socket.nio.NioSocketChannel; 9 | import io.netty.handler.codec.http.DefaultFullHttpRequest; 10 | import io.netty.handler.codec.http.HttpHeaders; 11 | import io.netty.handler.codec.http.HttpMethod; 12 | import io.netty.handler.codec.http.HttpVersion; 13 | 14 | import java.net.URI; 15 | 16 | /** 17 | * @author: liwh 18 | * @Date: 2017/2/7. 19 | * @Description:选项操作 20 | */ 21 | public class OptionHandler { 22 | 23 | private static volatile Bootstrap bootstrap; 24 | private static EventLoopGroup eventLoopGroup; 25 | 26 | /** 27 | * 启动netty连接,建立客户端和服务端的连接 28 | * @throws Exception 29 | */ 30 | public void start() throws Exception{ 31 | try { 32 | eventLoopGroup=new NioEventLoopGroup(); 33 | bootstrap=new Bootstrap(); 34 | bootstrap.group(eventLoopGroup); 35 | bootstrap.channel(NioSocketChannel.class); 36 | bootstrap.option(ChannelOption.SO_KEEPALIVE,true); 37 | bootstrap.handler(new IntermediaryChannelHandler()); 38 | 39 | ChannelFuture f =bootstrap.connect("127.0.0.1",9003).sync(); 40 | URI uri =new URI(".."); 41 | /**DefaultFullHttpRequest --模拟浏览器请求,http的版本|http的请求方式|请求url**/ 42 | DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, uri.toASCIIString()); 43 | /*--======== 构建 http 请求 =========--*/ 44 | request.headers().set(HttpHeaders.Names.HOST, "127.0.0.1"); 45 | request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE); 46 | request.headers().set(HttpHeaders.Names.CONTENT_LENGTH, request.content().readableBytes()); 47 | 48 | /*--======== 发送 http 请求 =========--*/ 49 | f.channel().write(request); 50 | f.channel().flush(); 51 | f.channel().closeFuture().sync(); 52 | 53 | }finally { 54 | eventLoopGroup.shutdownGracefully();//优雅退出 55 | } 56 | 57 | 58 | } 59 | 60 | /** 61 | * 暂停下载 -- 进入休眠 62 | * @throws Exception 63 | */ 64 | public void suspend() throws Exception{ 65 | eventLoopGroup.wait(); 66 | } 67 | 68 | /** 69 | * 继续下载 70 | * @throws Exception 71 | */ 72 | public void resume() throws Exception{ 73 | eventLoopGroup.next(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /netty-file-server/src/main/java/com/lwhtarena/netty/netty4/util/ObjectConvertUtil.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.netty4.util; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.lwhtarena.netty.netty4.model.*; 5 | 6 | /** 7 | * @author: liwh 8 | * @Date: 2016/11/17. 9 | * @Description:传输数据转化包 10 | */ 11 | public class ObjectConvertUtil { 12 | public static String convertModle(SecureModel secureModel){ 13 | RecvieMessage recevie = new RecvieMessage(); 14 | recevie.setData(JSON.toJSONString(secureModel)); 15 | recevie.setMsgType(Event.MESSAGE_TYPE_SECURE_MODEL); 16 | return JSON.toJSONString(recevie); 17 | } 18 | 19 | public static String convertModle(ResponseFile response){ 20 | RecvieMessage recevie = new RecvieMessage(); 21 | recevie.setData(JSON.toJSONString(response)); 22 | recevie.setMsgType(Event.MESSAGE_TYPE_RESPONSE_FILE); 23 | return JSON.toJSONString(recevie); 24 | } 25 | 26 | public static String convertModle(RequestFile requst){ 27 | RecvieMessage recevie = new RecvieMessage(); 28 | recevie.setData(JSON.toJSONString(requst)); 29 | recevie.setMsgType(Event.MESSAGE_TYPE_REQUEST_FILE); 30 | return JSON.toJSONString(recevie); 31 | } 32 | 33 | public static Object convertModle(String recviejson){ 34 | RecvieMessage recvie = (RecvieMessage) JSON.parseObject(recviejson,RecvieMessage.class); 35 | Object obj = null ; 36 | switch(recvie.getMsgType()){ 37 | case Event.MESSAGE_TYPE_SECURE_MODEL: 38 | obj = (SecureModel) JSON.parseObject(recvie.getData().toString(),SecureModel.class); 39 | break; 40 | case Event.MESSAGE_TYPE_REQUEST_FILE: 41 | obj = (RequestFile) JSON.parseObject(recvie.getData().toString(),RequestFile.class); 42 | break; 43 | case Event.MESSAGE_TYPE_RESPONSE_FILE: 44 | obj = (ResponseFile) JSON.parseObject(recvie.getData().toString(),ResponseFile.class); 45 | break; 46 | } 47 | return obj ; 48 | } 49 | 50 | public static String request(Object obj){ 51 | if( obj instanceof SecureModel ) { 52 | SecureModel secureModel = (SecureModel)obj; 53 | return convertModle(secureModel); 54 | } else if ( obj instanceof RequestFile) { 55 | RequestFile requestFile = (RequestFile)obj; 56 | return convertModle(requestFile); 57 | } else if ( obj instanceof ResponseFile) { 58 | ResponseFile responseFile = (ResponseFile)obj; 59 | return convertModle(responseFile); 60 | } else { 61 | return null ; 62 | } 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /netty-server/src/main/java/com/lwhtarena/netty/tutorial03/util/ObjectConvertUtil.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial03.util; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.lwhtarena.netty.tutorial03.model.*; 5 | 6 | /** 7 | * @author: liwh 8 | * @Date: 2016/11/17. 9 | * @Description:传输数据转化包 10 | */ 11 | public class ObjectConvertUtil { 12 | public static String convertModle(SecureModel secureModel){ 13 | RecvieMessage recevie = new RecvieMessage(); 14 | recevie.setData(JSON.toJSONString(secureModel)); 15 | recevie.setMsgType(Event.MESSAGE_TYPE_SECURE_MODEL); 16 | return JSON.toJSONString(recevie); 17 | } 18 | 19 | public static String convertModle(ResponseFile response){ 20 | RecvieMessage recevie = new RecvieMessage(); 21 | recevie.setData(JSON.toJSONString(response)); 22 | recevie.setMsgType(Event.MESSAGE_TYPE_RESPONSE_FILE); 23 | return JSON.toJSONString(recevie); 24 | } 25 | 26 | public static String convertModle(RequestFile requst){ 27 | RecvieMessage recevie = new RecvieMessage(); 28 | recevie.setData(JSON.toJSONString(requst)); 29 | recevie.setMsgType(Event.MESSAGE_TYPE_REQUEST_FILE); 30 | return JSON.toJSONString(recevie); 31 | } 32 | 33 | public static Object convertModle(String recviejson){ 34 | RecvieMessage recvie = (RecvieMessage) JSON.parseObject(recviejson,RecvieMessage.class); 35 | Object obj = null ; 36 | switch(recvie.getMsgType()){ 37 | case Event.MESSAGE_TYPE_SECURE_MODEL: 38 | obj = (SecureModel) JSON.parseObject(recvie.getData().toString(),SecureModel.class); 39 | break; 40 | case Event.MESSAGE_TYPE_REQUEST_FILE: 41 | obj = (RequestFile) JSON.parseObject(recvie.getData().toString(),RequestFile.class); 42 | break; 43 | case Event.MESSAGE_TYPE_RESPONSE_FILE: 44 | obj = (ResponseFile) JSON.parseObject(recvie.getData().toString(),ResponseFile.class); 45 | break; 46 | } 47 | return obj ; 48 | } 49 | 50 | public static String request(Object obj){ 51 | if( obj instanceof SecureModel) { 52 | SecureModel secureModel = (SecureModel)obj; 53 | return convertModle(secureModel); 54 | } else if ( obj instanceof RequestFile) { 55 | RequestFile requestFile = (RequestFile)obj; 56 | return convertModle(requestFile); 57 | } else if ( obj instanceof ResponseFile) { 58 | ResponseFile responseFile = (ResponseFile)obj; 59 | return convertModle(responseFile); 60 | } else { 61 | return null ; 62 | } 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /nettyy-demo01/src/main/java/com/lwhtarena/netty/netty4/util/ObjectConvertUtil.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.netty4.util; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.lwhtarena.netty.netty4.model.*; 5 | 6 | /** 7 | * 传输数据转化包 8 | * @author: liwh 9 | * @Date: 2016/11/17. 10 | * @Description:传输数据转化包 11 | */ 12 | public class ObjectConvertUtil { 13 | 14 | public static String convertModle(SecureModel secureModel){ 15 | RecvieMessage recevie = new RecvieMessage(); 16 | recevie.setData(JSON.toJSONString(secureModel)); 17 | recevie.setMsgType(Event.MESSAGE_TYPE_SECURE_MODEL); 18 | return JSON.toJSONString(recevie); 19 | } 20 | 21 | public static String convertModle(ResponseFile response){ 22 | RecvieMessage recevie = new RecvieMessage(); 23 | recevie.setData(JSON.toJSONString(response)); 24 | recevie.setMsgType(Event.MESSAGE_TYPE_RESPONSE_FILE); 25 | return JSON.toJSONString(recevie); 26 | } 27 | 28 | public static String convertModle(RequestFile requst){ 29 | RecvieMessage recevie = new RecvieMessage(); 30 | recevie.setData(JSON.toJSONString(requst)); 31 | recevie.setMsgType(Event.MESSAGE_TYPE_REQUEST_FILE); 32 | return JSON.toJSONString(recevie); 33 | } 34 | 35 | public static Object convertModle(String recviejson){ 36 | RecvieMessage recvie = (RecvieMessage) JSON.parseObject(recviejson,RecvieMessage.class); 37 | Object obj = null ; 38 | switch(recvie.getMsgType()){ 39 | case Event.MESSAGE_TYPE_SECURE_MODEL: 40 | obj = (SecureModel) JSON.parseObject(recvie.getData().toString(),SecureModel.class); 41 | break; 42 | case Event.MESSAGE_TYPE_REQUEST_FILE: 43 | obj = (RequestFile) JSON.parseObject(recvie.getData().toString(),RequestFile.class); 44 | break; 45 | case Event.MESSAGE_TYPE_RESPONSE_FILE: 46 | obj = (ResponseFile) JSON.parseObject(recvie.getData().toString(),ResponseFile.class); 47 | break; 48 | } 49 | return obj ; 50 | } 51 | 52 | public static String request(Object obj){ 53 | if( obj instanceof SecureModel ) { 54 | SecureModel secureModel = (SecureModel)obj; 55 | return convertModle(secureModel); 56 | } else if ( obj instanceof RequestFile) { 57 | RequestFile requestFile = (RequestFile)obj; 58 | return convertModle(requestFile); 59 | } else if ( obj instanceof ResponseFile) { 60 | ResponseFile responseFile = (ResponseFile)obj; 61 | return convertModle(responseFile); 62 | } else { 63 | return null ; 64 | } 65 | 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /netty-file-client/src/main/java/com/lwhtarena/netty/netty4/util/ObjectConvertUtil.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.netty4.util; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.lwhtarena.netty.netty4.model.*; 5 | 6 | /** 7 | * 传输数据转化包 8 | * @author: liwh 9 | * @Date: 2016/11/17. 10 | * @Description:传输数据转化包 11 | */ 12 | public class ObjectConvertUtil { 13 | 14 | public static String convertModle(SecureModel secureModel){ 15 | RecvieMessage recevie = new RecvieMessage(); 16 | recevie.setData(JSON.toJSONString(secureModel)); 17 | recevie.setMsgType(Event.MESSAGE_TYPE_SECURE_MODEL); 18 | return JSON.toJSONString(recevie); 19 | } 20 | 21 | public static String convertModle(ResponseFile response){ 22 | RecvieMessage recevie = new RecvieMessage(); 23 | recevie.setData(JSON.toJSONString(response)); 24 | recevie.setMsgType(Event.MESSAGE_TYPE_RESPONSE_FILE); 25 | return JSON.toJSONString(recevie); 26 | } 27 | 28 | public static String convertModle(RequestFile requst){ 29 | RecvieMessage recevie = new RecvieMessage(); 30 | recevie.setData(JSON.toJSONString(requst)); 31 | recevie.setMsgType(Event.MESSAGE_TYPE_REQUEST_FILE); 32 | return JSON.toJSONString(recevie); 33 | } 34 | 35 | public static Object convertModle(String recviejson){ 36 | RecvieMessage recvie = (RecvieMessage) JSON.parseObject(recviejson,RecvieMessage.class); 37 | Object obj = null ; 38 | switch(recvie.getMsgType()){ 39 | case Event.MESSAGE_TYPE_SECURE_MODEL: 40 | obj = (SecureModel) JSON.parseObject(recvie.getData().toString(),SecureModel.class); 41 | break; 42 | case Event.MESSAGE_TYPE_REQUEST_FILE: 43 | obj = (RequestFile) JSON.parseObject(recvie.getData().toString(),RequestFile.class); 44 | break; 45 | case Event.MESSAGE_TYPE_RESPONSE_FILE: 46 | obj = (ResponseFile) JSON.parseObject(recvie.getData().toString(),ResponseFile.class); 47 | break; 48 | } 49 | return obj ; 50 | } 51 | 52 | public static String request(Object obj){ 53 | if( obj instanceof SecureModel ) { 54 | SecureModel secureModel = (SecureModel)obj; 55 | return convertModle(secureModel); 56 | } else if ( obj instanceof RequestFile) { 57 | RequestFile requestFile = (RequestFile)obj; 58 | return convertModle(requestFile); 59 | } else if ( obj instanceof ResponseFile) { 60 | ResponseFile responseFile = (ResponseFile)obj; 61 | return convertModle(responseFile); 62 | } else { 63 | return null ; 64 | } 65 | 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /netty-client/src/main/java/com/lwhtarena/netty/tutorial03/util/ObjectConvertUtil.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.tutorial03.util; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.lwhtarena.netty.tutorial03.model.*; 5 | 6 | /** 7 | * 传输数据转化包 8 | * @author: liwh 9 | * @Date: 2016/11/17. 10 | * @Description:传输数据转化包 11 | */ 12 | public class ObjectConvertUtil { 13 | 14 | public static String convertModle(SecureModel secureModel){ 15 | RecvieMessage recevie = new RecvieMessage(); 16 | recevie.setData(JSON.toJSONString(secureModel)); 17 | recevie.setMsgType(Event.MESSAGE_TYPE_SECURE_MODEL); 18 | return JSON.toJSONString(recevie); 19 | } 20 | 21 | public static String convertModle(ResponseFile response){ 22 | RecvieMessage recevie = new RecvieMessage(); 23 | recevie.setData(JSON.toJSONString(response)); 24 | recevie.setMsgType(Event.MESSAGE_TYPE_RESPONSE_FILE); 25 | return JSON.toJSONString(recevie); 26 | } 27 | 28 | public static String convertModle(RequestFile requst){ 29 | RecvieMessage recevie = new RecvieMessage(); 30 | recevie.setData(JSON.toJSONString(requst)); 31 | recevie.setMsgType(Event.MESSAGE_TYPE_REQUEST_FILE); 32 | return JSON.toJSONString(recevie); 33 | } 34 | 35 | public static Object convertModle(String recviejson){ 36 | RecvieMessage recvie = (RecvieMessage) JSON.parseObject(recviejson,RecvieMessage.class); 37 | Object obj = null ; 38 | switch(recvie.getMsgType()){ 39 | case Event.MESSAGE_TYPE_SECURE_MODEL: 40 | obj = (SecureModel) JSON.parseObject(recvie.getData().toString(),SecureModel.class); 41 | break; 42 | case Event.MESSAGE_TYPE_REQUEST_FILE: 43 | obj = (RequestFile) JSON.parseObject(recvie.getData().toString(),RequestFile.class); 44 | break; 45 | case Event.MESSAGE_TYPE_RESPONSE_FILE: 46 | obj = (ResponseFile) JSON.parseObject(recvie.getData().toString(),ResponseFile.class); 47 | break; 48 | } 49 | return obj ; 50 | } 51 | 52 | public static String request(Object obj){ 53 | if( obj instanceof SecureModel ) { 54 | SecureModel secureModel = (SecureModel)obj; 55 | return convertModle(secureModel); 56 | } else if ( obj instanceof RequestFile) { 57 | RequestFile requestFile = (RequestFile)obj; 58 | return convertModle(requestFile); 59 | } else if ( obj instanceof ResponseFile) { 60 | ResponseFile responseFile = (ResponseFile)obj; 61 | return convertModle(responseFile); 62 | } else { 63 | return null ; 64 | } 65 | 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /netty-file-server/src/main/java/com/lwhtarena/netty/netty4/server/FileTransferServer.java: -------------------------------------------------------------------------------- 1 | package com.lwhtarena.netty.netty4.server; 2 | 3 | 4 | import com.lwhtarena.netty.netty4.util.FileTransferProperties; 5 | import io.netty.bootstrap.ServerBootstrap; 6 | import io.netty.channel.ChannelFuture; 7 | import io.netty.channel.ChannelOption; 8 | import io.netty.channel.EventLoopGroup; 9 | import io.netty.channel.nio.NioEventLoopGroup; 10 | import io.netty.channel.socket.nio.NioServerSocketChannel; 11 | import org.apache.log4j.Logger; 12 | import org.apache.log4j.PropertyConfigurator; 13 | import org.springframework.core.io.FileSystemResourceLoader; 14 | 15 | import java.io.IOException; 16 | 17 | /** 18 | * @author: liwh 19 | * @Date: 2016/11/17. 20 | * @Description: 21 | */ 22 | public class FileTransferServer { 23 | private Logger log = Logger.getLogger(FileTransferServer.class); 24 | 25 | public void bind(int port) throws Exception { 26 | EventLoopGroup bossGroup = new NioEventLoopGroup(); 27 | EventLoopGroup workerGroup = new NioEventLoopGroup(); 28 | try { 29 | ServerBootstrap b = new ServerBootstrap(); 30 | b.group(bossGroup, workerGroup) 31 | .channel(NioServerSocketChannel.class) 32 | .option(ChannelOption.SO_BACKLOG, 1024) 33 | .childHandler(new FileChannelInitializer()); 34 | 35 | log.info("bind port:"+port); 36 | 37 | ChannelFuture f = b.bind(port).sync(); 38 | f.channel().closeFuture().sync(); 39 | } finally { 40 | bossGroup.shutdownGracefully(); 41 | workerGroup.shutdownGracefully(); 42 | } 43 | } 44 | 45 | private static void init(){ 46 | try { 47 | //请把加载属性文件放在 加载日志配置的上面,因为读取日志输出的目录配置在 属性文件里面 48 | FileTransferProperties.load("classpath:systemConfig.properties"); 49 | 50 | System.setProperty("WORKDIR", FileTransferProperties.getString("WORKDIR","/")); 51 | 52 | PropertyConfigurator.configure(new FileSystemResourceLoader().getResource( 53 | "classpath:log4j.xml").getInputStream()); 54 | } catch (IOException e){ 55 | e.printStackTrace(); 56 | } 57 | } 58 | 59 | public static void main(String[] args) { 60 | init(); 61 | // 获取端口 62 | int port = FileTransferProperties.getInt("port",10012); 63 | 64 | if (args != null && args.length > 0) { 65 | try { 66 | port = Integer.valueOf(args[0]); 67 | } catch (NumberFormatException e) { 68 | e.printStackTrace(); 69 | } 70 | } 71 | 72 | try { 73 | new FileTransferServer().bind(port); 74 | } catch (Exception e) { 75 | e.printStackTrace(); 76 | } 77 | } 78 | } 79 | --------------------------------------------------------------------------------
简单的工具类
netty 传输序列化对象
负责文件的存储
7 | * 8 | 程序说明: 9 | 1,刚开始程序的等待的。 10 | 2,你输入‘g’回车后会运行。 11 | 3,你输入‘w’回车后会再次等待。 12 | 4,再次输入‘g’回车后又会运行。 13 | 5,输入‘s'回车,会终止程序。 14 | 6,这里将控制线程设置成了Deamon的形式,因为线程t由线程c控制可以终止,而线程c始终无法终止,所以把它设置 15 | 为后台线程,当让控制的线程t退出时,所有的前台线程都结束了,这样线程c就可以自动退出。 16 | *
RandomAccessFile是用来访问那些保存数据记录的文件的,你就 11 | * 可以用seek( )方法来访问记录,并进行读写了。这些记录的大小不必相同;但是其大小和 12 | * 位置必须是可知的。但是该类仅限于操作文件。
创建和实现HelloServerInitializer
实现一个能够像服务端发送文字的功能。服务端假如可以最好还能返回点消息给客户端,然客户端去显示。
处理Server响应的HttpClientInboundHandler
在项目的开发资源开发中,测试发现一个问题:将资源上传到服务器上,提示已经上传成功,但是当打开这个文件时发现失败,由于各种原因资源已经毁坏。怎么样能保证资源的完整性,处理办法就是用MD5验证文件的完整性。
任何一个字符串或文件,无论是可执行程序、图像文件、临时文件或者其他任何类型的文件,也不管它体积多大,都有且只有一个独一无二的MD5信息码,并且如果这个文件被修改过,它的MD5码也将随之改变。
MappedByteBuffer的读取/写入文件和普通I/O流的对比
要抓取的文件的信息,如文件保存的目录,名字,抓取文件的 URL 等
文件对象
这个例子演示了如何中止一个HTTP请求。 14 | * 15 | *
增加自己的逻辑HelloServerHandler
自己的Handler我们这里先去继承extends官网推荐的SimpleChannelInboundHandler 。在这里C,由于我们需求里面发送的是字符串。这里的C改写为String。
内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件。
有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问 13 | * 。这种解决办法能大大简化修改文件的代码。
fileChannel.map(FileChannel.MapMode mode, long position, long size)将此通道的文 16 | * 件区域直接映射到内存中。注意,你必须指明,它是从文件的哪个位置开始映射的,映射的范围又有多大; 17 | * 也就是说,它还可以映射一个大文件的某个小片断。
MappedByteBuffer是ByteBuffer的子类,因此它具备了ByteBuffer的所有方法,但新添了force()将 20 | * 缓冲区的内容强制刷新到存储设备中去、load()将存储设备中的数据加载到内存中、isLoaded()位置内存中 21 | * 的数据是否与存储设置上同步。这里只简单地演示了一下put()和get()方法,除此之外,你还可以使用 22 | * asCharBuffer( )之类的方法得到相应基本类型数据的缓冲视图后,可以方便的读写基本类型数据。
尽管映射写似乎要用到FileOutputStream,但是映射文件中的所有输出 必须使用RandomAccessFile, 46 | * 但如果只需要读时可以使用FileInputStream,写映射文件时一定要使用随机访问文件,可能写时要读的原因吧。
该程序创建了一个128Mb的文件,如果一次性读到内存可能导致内存溢出,但这里访问好像只是一瞬间的事, 49 | * 这是因为,真正调入内存的只是其中的一小部分,其余部分则被放在交换文件上。这样你就可以很方便地修改超 50 | * 大型的文件了(最大可以到2 GB)。注意,Java是调用操作系统的"文件映射机制"来提升性能的。
创建一个服务 HelloServer
定义了两个工作线程,一个命名为WorkerGroup,另一个命名为BossGroup。都是实例化NioEventLoopGroup。
这一点和3.x版本中基本思路是一致的。Worker线程用于管理线程为Boss线程服务。
EventLoopGroup,它是4.x版本提出来的一个新概念。类似于3.x版本中的线程。用于管理Channel连接的。
shutdownGraceFully(),翻译为中文就是优雅的全部关闭.
我们可以在DefaultEventExecutorGroup的父类MultithreadEventExecutorGroup中看到它的实现代码。关闭 47 | * 了全部EventExecutor数组child里面子元素。相比于3.x版本这是一个比较重大的改动。开发者可以很轻松的全部关闭, 48 | * 而不需要担心出现内存泄露。
java 线程的开始、暂停、继续
8 | * 一个需求:通过线程读取文件内容,并且可以控制线程的开始、暂停、继续,来控制读文件。在此记录下。 9 | 10 | 直接在主线程中,通过wait、notify、notifyAll去控制读文件的线程(子线程),报错:java.lang.IllegalMonitorStateException。 11 | 12 | 需要注意的几个问题: 13 | 14 | 1.任何一个时刻,对象的控制权(monitor)只能被一个线程拥有。 15 | 16 | 2.无论是执行对象的wait、notify还是notifyAll方法,必须保证当前运行的线程取得了该对象的控制权(monitor)。 17 | 18 | 3.如果在没有控制权的线程里执行对象的以上三种方法,就会报错java.lang.IllegalMonitorStateException。 19 | 20 | 4.JVM基于多线程,默认情况下不能保证运行时线程的时序性。 21 | 22 | 线程取得控制权的3种方法: 23 | 24 | 1.执行对象的某个同步实例方法。 25 | 26 | 2.执行对象对应类的同步静态方法。 27 | 28 | 3.执行对该对象加同步锁的同步块。 29 | 30 | 这里将开始、暂停、继续封装在线程类中,直接调用该实例的方法就行。 31 | *
中介客户端
http server
利用RandomAccessFile实现文件的多线程下载,即多线程下载一 8 | * 个文件时,将文件分成几块,每块用不同的线程进行下载。
下面是一个利用多线程在写文件时的例子,其中预先分配文件所需要的空间, 11 | * 然后在所分配的空间中进行分块,然后写入:
选项操作