作者 钟来

初始提交

正在显示 93 个修改的文件 包含 4237 行增加0 行删除
  1 +/target/
  2 +/.idea/
  3 +/.settings/
  4 +.classpath
  5 +.project
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
  3 + <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
  4 + <output url="file://$MODULE_DIR$/target/classes" />
  5 + <output-test url="file://$MODULE_DIR$/target/test-classes" />
  6 + <content url="file://$MODULE_DIR$">
  7 + <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
  8 + <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
  9 + <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
  10 + <excludeFolder url="file://$MODULE_DIR$/target" />
  11 + </content>
  12 + <orderEntry type="inheritedJdk" />
  13 + <orderEntry type="sourceFolder" forTests="false" />
  14 + <orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.12" level="project" />
  15 + <orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
  16 + <orderEntry type="library" name="Maven: io.netty:netty-all:4.1.30.Final" level="project" />
  17 + <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.6.3" level="project" />
  18 + <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.6.3" level="project" />
  19 + <orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.6.0" level="project" />
  20 + </component>
  21 +</module>
  1 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3 + <modelVersion>4.0.0</modelVersion>
  4 +
  5 + <groupId>com.waylau</groupId>
  6 + <artifactId>netty4-demos</artifactId>
  7 + <version>1.0.0</version>
  8 + <packaging>jar</packaging>
  9 +
  10 + <name>netty4-demos</name>
  11 + <url>http://www.waylau.com</url>
  12 +
  13 + <properties>
  14 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  15 + <version.jackson.core>2.6.3</version.jackson.core>
  16 + </properties>
  17 + <build>
  18 + <plugins>
  19 + <plugin>
  20 + <groupId>org.apache.maven.plugins</groupId>
  21 + <artifactId>maven-compiler-plugin</artifactId>
  22 + <version>3.2</version>
  23 + <configuration>
  24 + <optimize>true</optimize>
  25 + <source>1.7</source>
  26 + <target>1.7</target>
  27 + </configuration>
  28 + </plugin>
  29 +
  30 + </plugins>
  31 + </build>
  32 + <dependencies>
  33 + <dependency>
  34 + <groupId>junit</groupId>
  35 + <artifactId>junit</artifactId>
  36 + <version>4.12</version>
  37 + <scope>test</scope>
  38 + </dependency>
  39 +
  40 + <dependency>
  41 + <groupId>io.netty</groupId>
  42 + <artifactId>netty-all</artifactId>
  43 + <version>4.1.30.Final</version>
  44 + </dependency>
  45 + <dependency>
  46 + <groupId>com.fasterxml.jackson.core</groupId>
  47 + <artifactId>jackson-core</artifactId>
  48 + <version>${version.jackson.core}</version>
  49 + </dependency>
  50 + <dependency>
  51 + <groupId>com.fasterxml.jackson.core</groupId>
  52 + <artifactId>jackson-databind</artifactId>
  53 + <version>${version.jackson.core}</version>
  54 + </dependency>
  55 + </dependencies>
  56 +</project>
  1 +package com.waylau.netty;
  2 +
  3 +/**
  4 + * Hello world!
  5 + *
  6 + */
  7 +public class App
  8 +{
  9 + public static void main( String[] args )
  10 + {
  11 + System.out.println( "Hello World!" );
  12 + }
  13 +}
  1 +package com.waylau.netty;
  2 +
  3 +import java.io.IOException;
  4 +import java.io.OutputStream;
  5 +import java.net.Socket;
  6 +
  7 +/**
  8 + * 测试用的 TCP 客户端
  9 + *
  10 + * @author waylau.com
  11 + * @date 2015-2-26
  12 + */
  13 +public class TcpClient {
  14 +
  15 + public static void main(String[] args) throws IOException {
  16 + Socket socket = null;
  17 + OutputStream out = null;
  18 +
  19 + try {
  20 +
  21 + socket = new Socket("localhost", 8023);
  22 + out = socket.getOutputStream();
  23 +
  24 + // 请求服务器
  25 + String lines = "床前明月光\r\n疑是地上霜\r\n举头望明月\r\n低头思故乡\r\n";
  26 + byte[] outputBytes = lines.getBytes("UTF-8");
  27 + out.write(outputBytes);
  28 + out.flush();
  29 +
  30 + } finally {
  31 + // 关闭连接
  32 + out.close();
  33 + socket.close();
  34 + }
  35 +
  36 + }
  37 +
  38 +}
  1 +package com.waylau.netty.demo.codec.jackcon;
  2 +
  3 +import java.util.List;
  4 +import java.util.Map;
  5 +
  6 +/**
  7 + * 说明:一个用户 POJO
  8 + *
  9 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月9日
  10 + */
  11 +public class JacksonBean {
  12 +
  13 + private int age;
  14 + private String name;
  15 + private List<String> sons;
  16 + private Map<String, String> addrs;
  17 +
  18 + public int getAge() {
  19 + return age;
  20 + }
  21 + public void setAge(int age) {
  22 + this.age = age;
  23 + }
  24 + public String getName() {
  25 + return name;
  26 + }
  27 + public void setName(String name) {
  28 + this.name = name;
  29 + }
  30 + public List<String> getSons() {
  31 + return sons;
  32 + }
  33 + public void setSons(List<String> sons) {
  34 + this.sons = sons;
  35 + }
  36 + public Map<String, String> getAddrs() {
  37 + return addrs;
  38 + }
  39 + public void setAddrs(Map<String, String> addrs) {
  40 + this.addrs = addrs;
  41 + }
  42 + /**
  43 + *
  44 + */
  45 + public JacksonBean() {
  46 + // TODO Auto-generated constructor stub
  47 + }
  48 +
  49 +}
  1 +package com.waylau.netty.demo.codec.jackcon;
  2 +
  3 +import java.util.ArrayList;
  4 +import java.util.HashMap;
  5 +import java.util.List;
  6 +import java.util.Map;
  7 +
  8 +import io.netty.bootstrap.Bootstrap;
  9 +import io.netty.channel.Channel;
  10 +import io.netty.channel.EventLoopGroup;
  11 +import io.netty.channel.nio.NioEventLoopGroup;
  12 +import io.netty.channel.socket.nio.NioSocketChannel;
  13 +
  14 +
  15 +/**
  16 + * 说明:Jackson json-客户端
  17 + *
  18 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月7日
  19 + */
  20 +public class JacksonClient {
  21 +
  22 + public static void main(String[] args) throws Exception{
  23 + new JacksonClient("localhost", 8082).run();
  24 + }
  25 +
  26 + private final String host;
  27 + private final int port;
  28 +
  29 + public JacksonClient(String host, int port){
  30 + this.host = host;
  31 + this.port = port;
  32 + }
  33 +
  34 + public void run() throws Exception{
  35 + EventLoopGroup group = new NioEventLoopGroup();
  36 + try {
  37 + Bootstrap bootstrap = new Bootstrap()
  38 + .group(group)
  39 + .channel(NioSocketChannel.class)
  40 + .handler(new JacksonClientHandlerInitializer());
  41 +
  42 + Channel channel = bootstrap.connect(host, port).sync().channel();
  43 +
  44 + // 发送对象
  45 + JacksonBean user = new JacksonBean();
  46 + user.setAge(27);
  47 + user.setName("waylau");
  48 + List<String> sons = new ArrayList<String>();
  49 + for (int i = 0;i <10; i++) {
  50 + sons.add("Lucy"+i);
  51 + sons.add("Lily"+i);
  52 + }
  53 +
  54 + user.setSons(sons);
  55 + Map<String, String> addrs = new HashMap<String, String>();
  56 + for (int i = 0;i <10; i++) {
  57 + addrs.put("001"+i, "18998366112");
  58 + addrs.put("002"+i, "15014965012");
  59 + }
  60 +
  61 + user.setAddrs(addrs);
  62 + channel.write(user);
  63 + channel.flush();
  64 +
  65 + // 等待连接关闭
  66 + channel.closeFuture().sync();
  67 + } catch (Exception e) {
  68 + e.printStackTrace();
  69 + } finally {
  70 + group.shutdownGracefully();
  71 + }
  72 +
  73 + }
  74 +
  75 +}
  1 +/**
  2 + *
  3 + */
  4 +package com.waylau.netty.demo.codec.jackcon;
  5 +
  6 +import io.netty.channel.ChannelHandlerContext;
  7 +import io.netty.channel.SimpleChannelInboundHandler;
  8 +
  9 +/**
  10 + * 说明:处理器
  11 + *
  12 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月7日
  13 + */
  14 +public class JacksonClientHandler extends
  15 + SimpleChannelInboundHandler<Object> {
  16 +
  17 + @Override
  18 + protected void channelRead0(ChannelHandlerContext ctx, Object obj)
  19 + throws Exception {
  20 + String jsonString = "";
  21 + if (obj instanceof JacksonBean) {
  22 + JacksonBean user = (JacksonBean) obj;
  23 +
  24 + jsonString = JacksonMapper.getInstance().writeValueAsString(user); // 对象转为json字符串
  25 + } else {
  26 + jsonString = JacksonMapper.getInstance().writeValueAsString(obj); // 对象转为json字符串
  27 + }
  28 + System.out.println("Client get msg form Server -" + jsonString);
  29 + }
  30 +
  31 +}
  1 +package com.waylau.netty.demo.codec.jackcon;
  2 +
  3 +import io.netty.channel.Channel;
  4 +import io.netty.channel.ChannelInitializer;
  5 +import io.netty.channel.ChannelPipeline;
  6 +
  7 +/**
  8 + * 说明:处理器初始化
  9 + *
  10 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月6日
  11 + */
  12 +public class JacksonClientHandlerInitializer extends
  13 + ChannelInitializer<Channel> {
  14 +
  15 +
  16 + @Override
  17 + protected void initChannel(Channel ch) throws Exception {
  18 + ChannelPipeline pipeline = ch.pipeline();
  19 + pipeline.addLast(new JacksonDecoder<JacksonBean>(JacksonBean.class));
  20 + pipeline.addLast(new JacksonEncoder());
  21 + pipeline.addLast(new JacksonClientHandler());
  22 + }
  23 +}
  1 +package com.waylau.netty.demo.codec.jackcon;
  2 +
  3 +import java.util.List;
  4 +
  5 +import io.netty.buffer.ByteBuf;
  6 +import io.netty.buffer.ByteBufInputStream;
  7 +import io.netty.channel.ChannelHandlerContext;
  8 +import io.netty.handler.codec.ByteToMessageDecoder;
  9 +
  10 +/**
  11 + * 说明:Jackson json 解码器
  12 + *
  13 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月9日
  14 + */
  15 +public class JacksonDecoder<T> extends ByteToMessageDecoder {
  16 +
  17 + private final Class<T> clazz;
  18 + /**
  19 + *
  20 + */
  21 + public JacksonDecoder(Class<T> clazz) {
  22 + this.clazz = clazz;
  23 + }
  24 +
  25 + /*
  26 + * (non-Javadoc)
  27 + *
  28 + * @see io.netty.handler.codec.ByteToMessageDecoder#decode(io.netty.channel.
  29 + * ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List)
  30 + */
  31 + @Override
  32 + protected void decode(ChannelHandlerContext ctx, ByteBuf in,
  33 + List<Object> out) throws Exception {
  34 + ByteBufInputStream byteBufInputStream = new ByteBufInputStream(in);
  35 + out.add(JacksonMapper.getInstance().readValue(byteBufInputStream, clazz));
  36 +
  37 + }
  38 +
  39 +}
  1 +/**
  2 + *
  3 + */
  4 +package com.waylau.netty.demo.codec.jackcon;
  5 +
  6 +
  7 +import com.fasterxml.jackson.databind.ObjectMapper;
  8 +
  9 +import io.netty.buffer.ByteBuf;
  10 +import io.netty.buffer.ByteBufOutputStream;
  11 +import io.netty.channel.ChannelHandlerContext;
  12 +import io.netty.handler.codec.MessageToByteEncoder;
  13 +
  14 +/**
  15 + * 说明:Jackson json 编码器
  16 + *
  17 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月9日
  18 + */
  19 +public class JacksonEncoder extends MessageToByteEncoder<Object> {
  20 +
  21 + @Override
  22 + protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out)
  23 + throws Exception {
  24 +
  25 + ObjectMapper mapper = JacksonMapper.getInstance(); // create once, reuse
  26 +// byte[] body = mapper.writeValueAsBytes(msg); // 将对象转换为byte
  27 +// out.writeBytes(body); // 消息体中包含我们要发送的数据
  28 + ByteBufOutputStream byteBufOutputStream = new ByteBufOutputStream(out);
  29 + mapper.writeValue(byteBufOutputStream, msg);
  30 + }
  31 +
  32 +}
  33 +
  1 +package com.waylau.netty.demo.codec.jackcon;
  2 +
  3 +import com.fasterxml.jackson.databind.ObjectMapper;
  4 +
  5 +/**
  6 + * 说明:ObjectMapper 单例。create once, reuse
  7 + *
  8 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月9日
  9 + */
  10 +public class JacksonMapper {
  11 +
  12 + private static final ObjectMapper MAPPER = new ObjectMapper();
  13 +
  14 + /**
  15 + * create once, reuse
  16 + * @return ObjectMapper 单例
  17 + */
  18 + public static ObjectMapper getInstance() {
  19 +
  20 + return MAPPER;
  21 + }
  22 +
  23 +}
  1 +package com.waylau.netty.demo.codec.jackcon;
  2 +
  3 +import io.netty.bootstrap.ServerBootstrap;
  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.NioServerSocketChannel;
  9 +import io.netty.handler.logging.LogLevel;
  10 +import io.netty.handler.logging.LoggingHandler;
  11 +
  12 +/**
  13 + * 说明:序列化服务器
  14 + *
  15 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月6日
  16 + */
  17 +public final class JacksonServer {
  18 +
  19 + static final int PORT = 8082;
  20 +
  21 + public static void main(String[] args) throws Exception {
  22 +
  23 + // Configure the server.
  24 + EventLoopGroup bossGroup = new NioEventLoopGroup(1);
  25 + EventLoopGroup workerGroup = new NioEventLoopGroup();
  26 + try {
  27 + ServerBootstrap b = new ServerBootstrap();
  28 + b.group(bossGroup, workerGroup)
  29 + .channel(NioServerSocketChannel.class)
  30 + .option(ChannelOption.SO_BACKLOG, 100)
  31 + .childOption(ChannelOption.SO_KEEPALIVE, true)
  32 + .handler(new LoggingHandler(LogLevel.INFO))
  33 + .childHandler(new JacksonServerHandlerInitializer());
  34 +
  35 + // Start the server.
  36 + ChannelFuture f = b.bind(PORT).sync();
  37 +
  38 + // Wait until the server socket is closed.
  39 + f.channel().closeFuture().sync();
  40 + } finally {
  41 + // Shut down all event loops to terminate all threads.
  42 + bossGroup.shutdownGracefully();
  43 + workerGroup.shutdownGracefully();
  44 + }
  45 + }
  46 +}
  1 +package com.waylau.netty.demo.codec.jackcon;
  2 +
  3 +import io.netty.channel.Channel;
  4 +import io.netty.channel.ChannelHandlerContext;
  5 +import io.netty.channel.SimpleChannelInboundHandler;
  6 +
  7 +/**
  8 + * 说明:处理器
  9 + *
  10 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月7日
  11 + */
  12 +public class JacksonServerHandler extends SimpleChannelInboundHandler<Object> {
  13 +
  14 +
  15 + @Override
  16 + protected void channelRead0(ChannelHandlerContext ctx, Object obj)
  17 + throws Exception {
  18 + String jsonString = "";
  19 + if (obj instanceof JacksonBean) {
  20 + JacksonBean user = (JacksonBean)obj;
  21 +
  22 + ctx.writeAndFlush(user);
  23 +
  24 + jsonString = JacksonMapper.getInstance().writeValueAsString(user); // 对象转为json字符串
  25 +
  26 + } else {
  27 + ctx.writeAndFlush(obj);
  28 + jsonString = JacksonMapper.getInstance().writeValueAsString(obj); // 对象转为json字符串
  29 + }
  30 +
  31 + System.out.println("Server get msg form Client -" + jsonString);
  32 + }
  33 +
  34 + @Override
  35 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  36 + Channel incoming = ctx.channel();
  37 + System.out.println("SimpleChatClient:"+incoming.remoteAddress()+"异常");
  38 + // 当出现异常就关闭连接
  39 + cause.printStackTrace();
  40 + ctx.close();
  41 + }
  42 +}
  1 +package com.waylau.netty.demo.codec.jackcon;
  2 +
  3 +import io.netty.channel.Channel;
  4 +import io.netty.channel.ChannelInitializer;
  5 +import io.netty.channel.ChannelPipeline;
  6 +
  7 +/**
  8 + * 说明:序列化服务器初始化
  9 + *
  10 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月6日
  11 + */
  12 +public class JacksonServerHandlerInitializer extends
  13 + ChannelInitializer<Channel> {
  14 +
  15 +
  16 + @Override
  17 + protected void initChannel(Channel ch) throws Exception {
  18 + ChannelPipeline pipeline = ch.pipeline();
  19 + pipeline.addLast(new JacksonDecoder<JacksonBean>(JacksonBean.class));
  20 + pipeline.addLast(new JacksonEncoder());
  21 + pipeline.addLast(new JacksonServerHandler());
  22 + }
  23 +}
  1 +package com.waylau.netty.demo.codec.jackcon;
  2 +
  3 +import java.io.File;
  4 +import java.io.IOException;
  5 +
  6 +import com.fasterxml.jackson.core.JsonEncoding;
  7 +import com.fasterxml.jackson.core.JsonFactory;
  8 +import com.fasterxml.jackson.core.JsonGenerationException;
  9 +import com.fasterxml.jackson.core.JsonGenerator;
  10 +
  11 +/**
  12 + * 说明:
  13 + *
  14 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月8日
  15 + */
  16 +public class JsonGeneratorDemo {
  17 +
  18 + private static final String FILE_PATH = "d:\\user.json";
  19 +
  20 + /**
  21 + *
  22 + */
  23 + public JsonGeneratorDemo() {
  24 + // TODO Auto-generated constructor stub
  25 + }
  26 +
  27 + /**
  28 + * @param args
  29 + * @throws IOException
  30 + */
  31 + public static void main(String[] args) throws IOException {
  32 + try {
  33 +
  34 + JsonFactory jfactory = new JsonFactory();
  35 +
  36 + JsonGenerator jGenerator = jfactory.createJsonGenerator(new File(
  37 + FILE_PATH), JsonEncoding.UTF8);
  38 + jGenerator.writeStartObject(); // {
  39 +
  40 + jGenerator.writeStringField("name", "mkyong"); // "name" : "mkyong"
  41 + jGenerator.writeNumberField("age", 29); // "age" : 29
  42 +
  43 + jGenerator.writeFieldName("messages"); // "messages" :
  44 + jGenerator.writeStartArray(); // [
  45 +
  46 + jGenerator.writeString("msg 1"); // "msg 1"
  47 + jGenerator.writeString("msg 2"); // "msg 2"
  48 + jGenerator.writeString("msg 3"); // "msg 3"
  49 +
  50 + jGenerator.writeEndArray(); // ]
  51 +
  52 + jGenerator.writeEndObject(); // }
  53 +
  54 + jGenerator.close();
  55 +
  56 + } catch (JsonGenerationException e) {
  57 + e.printStackTrace();
  58 + }
  59 + }
  60 +}
  1 +/**
  2 + *
  3 + */
  4 +package com.waylau.netty.demo.codec.jackcon;
  5 +
  6 +import java.io.File;
  7 +import java.io.IOException;
  8 +
  9 +import com.fasterxml.jackson.core.JsonFactory;
  10 +import com.fasterxml.jackson.core.JsonParseException;
  11 +import com.fasterxml.jackson.core.JsonParser;
  12 +import com.fasterxml.jackson.core.JsonToken;
  13 +
  14 +/**
  15 + * 说明:
  16 + *
  17 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月8日
  18 + */
  19 +public class JsonParserDemo {
  20 +
  21 + private static final String FILE_PATH = "d:\\user.json";
  22 +
  23 + /**
  24 + *
  25 + */
  26 + public JsonParserDemo() {
  27 + // TODO Auto-generated constructor stub
  28 + }
  29 +
  30 + /**
  31 + * @param args
  32 + * @throws IOException
  33 + * @throws JsonParseException
  34 + */
  35 + public static void main(String[] args) throws JsonParseException,
  36 + IOException {
  37 +
  38 + JsonFactory jfactory = new JsonFactory();
  39 +
  40 + JsonParser jParser = jfactory.createJsonParser(new File(FILE_PATH));
  41 +
  42 + // loop until token equal to "}"
  43 + while (jParser.nextToken() != JsonToken.END_OBJECT) {
  44 +
  45 + String fieldname = jParser.getCurrentName();
  46 + if ("name".equals(fieldname)) {
  47 +
  48 + // current token is "name",
  49 + // move to next, which is "name"'s value
  50 + jParser.nextToken();
  51 + System.out.println(jParser.getText()); // display mkyong
  52 +
  53 + }
  54 +
  55 + if ("age".equals(fieldname)) {
  56 +
  57 + // current token is "age",
  58 + // move to next, which is "name"'s value
  59 + jParser.nextToken();
  60 + System.out.println(jParser.getIntValue()); // display 29
  61 +
  62 + }
  63 +
  64 + if ("messages".equals(fieldname)) {
  65 +
  66 + jParser.nextToken(); // current token is "[", move next
  67 +
  68 + // messages is array, loop until token equal to "]"
  69 + while (jParser.nextToken() != JsonToken.END_ARRAY) {
  70 +
  71 + // display msg1, msg2, msg3
  72 + System.out.println(jParser.getText());
  73 +
  74 + }
  75 +
  76 + }
  77 +
  78 + }
  79 + jParser.close();
  80 +
  81 + }
  82 +
  83 +}
  1 +/**
  2 + *
  3 + */
  4 +/**
  5 + * 说明:使用 Jackson json 来执行序列化
  6 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月8日
  7 + */
  8 +package com.waylau.netty.demo.codec.jackcon;
  1 +package com.waylau.netty.demo.codec.serialization;
  2 +
  3 +import java.io.Serializable;
  4 +
  5 +/**
  6 + * 说明:一个用户 POJO
  7 + *
  8 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月7日
  9 + */
  10 +public class SerializationBean implements Serializable{
  11 +
  12 + /**
  13 + *
  14 + */
  15 + private static final long serialVersionUID = 3235432002462705915L;
  16 + private int age;
  17 + private String name;
  18 +
  19 + public int getAge() {
  20 + return age;
  21 + }
  22 + public void setAge(int age) {
  23 + this.age = age;
  24 + }
  25 + public String getName() {
  26 + return name;
  27 + }
  28 + public void setName(String name) {
  29 + this.name = name;
  30 + }
  31 +
  32 + /**
  33 + *
  34 + */
  35 + public SerializationBean() {
  36 + // TODO Auto-generated constructor stub
  37 + }
  38 +
  39 +}
  1 +package com.waylau.netty.demo.codec.serialization;
  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 +
  10 +/**
  11 + * 说明:序列化-客户端
  12 + *
  13 + * @author <a href="https://waylau.com">waylau.com</a> 2015年11月7日
  14 + */
  15 +public class SerializationClient {
  16 +
  17 + public static void main(String[] args) throws Exception{
  18 + new SerializationClient("localhost", 8082).run();
  19 + }
  20 +
  21 + private final String host;
  22 + private final int port;
  23 +
  24 + public SerializationClient(String host, int port){
  25 + this.host = host;
  26 + this.port = port;
  27 + }
  28 +
  29 + public void run() throws Exception{
  30 + EventLoopGroup group = new NioEventLoopGroup();
  31 + try {
  32 + Bootstrap bootstrap = new Bootstrap()
  33 + .group(group)
  34 + .channel(NioSocketChannel.class)
  35 + .handler(new SerializationClientHandlerInitializer());
  36 +
  37 + Channel channel = bootstrap.connect(host, port).sync().channel();
  38 +
  39 + SerializationBean user = new SerializationBean();
  40 +
  41 + for (int i = 0; i < 100; i++) {
  42 + user = new SerializationBean();
  43 + user.setAge(i);
  44 + user.setName("waylau");
  45 + channel.write(user);
  46 + }
  47 + channel.flush();
  48 +
  49 + // 等待连接关闭
  50 + channel.closeFuture().sync();
  51 + } catch (Exception e) {
  52 + e.printStackTrace();
  53 + } finally {
  54 + group.shutdownGracefully();
  55 + }
  56 +
  57 + }
  58 +
  59 +}
  1 +/**
  2 + *
  3 + */
  4 +package com.waylau.netty.demo.codec.serialization;
  5 +
  6 +import io.netty.channel.ChannelHandlerContext;
  7 +import io.netty.channel.SimpleChannelInboundHandler;
  8 +
  9 +/**
  10 + * 说明:处理器
  11 + *
  12 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月7日
  13 + */
  14 +public class SerializationClientHandler extends
  15 + SimpleChannelInboundHandler<Object> {
  16 +
  17 + @Override
  18 + protected void channelRead0(ChannelHandlerContext ctx, Object obj)
  19 + throws Exception {
  20 + if (obj instanceof SerializationBean) {
  21 + SerializationBean user = (SerializationBean) obj;
  22 + System.out.println("Client get msg form Server - name:"
  23 + + user.getName() + ";age:" + user.getAge());
  24 + }
  25 +
  26 + }
  27 +
  28 +}
  1 +package com.waylau.netty.demo.codec.serialization;
  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.serialization.ClassResolvers;
  7 +import io.netty.handler.codec.serialization.ObjectDecoder;
  8 +import io.netty.handler.codec.serialization.ObjectEncoder;
  9 +
  10 +/**
  11 + * 说明:处理器初始化
  12 + *
  13 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月6日
  14 + */
  15 +public class SerializationClientHandlerInitializer extends
  16 + ChannelInitializer<Channel> {
  17 +
  18 + private final static int MAX_OBJECT_SIZE = 1024 * 1024;
  19 +
  20 + @Override
  21 + protected void initChannel(Channel ch) throws Exception {
  22 + ChannelPipeline pipeline = ch.pipeline();
  23 + pipeline.addLast(new ObjectDecoder(MAX_OBJECT_SIZE,
  24 + ClassResolvers.weakCachingConcurrentResolver(this.getClass()
  25 + .getClassLoader())));
  26 + pipeline.addLast(new ObjectEncoder());
  27 + pipeline.addLast(new SerializationClientHandler());
  28 + }
  29 +}
  1 +package com.waylau.netty.demo.codec.serialization;
  2 +
  3 +import io.netty.bootstrap.ServerBootstrap;
  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.NioServerSocketChannel;
  9 +import io.netty.handler.logging.LogLevel;
  10 +import io.netty.handler.logging.LoggingHandler;
  11 +
  12 +/**
  13 + * 说明:序列化服务器
  14 + *
  15 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月6日
  16 + */
  17 +public final class SerializationServer {
  18 +
  19 + static final int PORT = 8082;
  20 +
  21 + public static void main(String[] args) throws Exception {
  22 +
  23 + // Configure the server.
  24 + EventLoopGroup bossGroup = new NioEventLoopGroup(1);
  25 + EventLoopGroup workerGroup = new NioEventLoopGroup();
  26 + try {
  27 + ServerBootstrap b = new ServerBootstrap();
  28 + b.group(bossGroup, workerGroup)
  29 + .channel(NioServerSocketChannel.class)
  30 + .option(ChannelOption.SO_BACKLOG, 100)
  31 + .childOption(ChannelOption.SO_KEEPALIVE, true)
  32 + .handler(new LoggingHandler(LogLevel.INFO))
  33 + .childHandler(new SerializationServerHandlerInitializer());
  34 +
  35 + // Start the server.
  36 + ChannelFuture f = b.bind(PORT).sync();
  37 +
  38 + // Wait until the server socket is closed.
  39 + f.channel().closeFuture().sync();
  40 + } finally {
  41 + // Shut down all event loops to terminate all threads.
  42 + bossGroup.shutdownGracefully();
  43 + workerGroup.shutdownGracefully();
  44 + }
  45 + }
  46 +}
  1 +package com.waylau.netty.demo.codec.serialization;
  2 +
  3 +import io.netty.channel.ChannelHandlerContext;
  4 +import io.netty.channel.SimpleChannelInboundHandler;
  5 +
  6 +/**
  7 + * 说明:处理器
  8 + *
  9 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月7日
  10 + */
  11 +public class SerializationServerHandler extends SimpleChannelInboundHandler<Object> {
  12 +
  13 +
  14 + @Override
  15 + protected void channelRead0(ChannelHandlerContext ctx, Object obj)
  16 + throws Exception {
  17 + if (obj instanceof SerializationBean) {
  18 + SerializationBean user = (SerializationBean)obj;
  19 + ctx.writeAndFlush(user);
  20 + System.out.println("Server get msg form Client - name:"+ user.getName() + ";age:" + user.getAge());
  21 + }
  22 + }
  23 +
  24 +}
  1 +package com.waylau.netty.demo.codec.serialization;
  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.serialization.ClassResolvers;
  7 +import io.netty.handler.codec.serialization.ObjectDecoder;
  8 +import io.netty.handler.codec.serialization.ObjectEncoder;
  9 +
  10 +/**
  11 + * 说明:序列化服务器初始化
  12 + *
  13 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月6日
  14 + */
  15 +public class SerializationServerHandlerInitializer extends
  16 + ChannelInitializer<Channel> {
  17 +
  18 + private final static int MAX_OBJECT_SIZE = 1024 * 1024;
  19 +
  20 + @Override
  21 + protected void initChannel(Channel ch) throws Exception {
  22 + ChannelPipeline pipeline = ch.pipeline();
  23 + pipeline.addLast(new ObjectDecoder(MAX_OBJECT_SIZE,
  24 + ClassResolvers.weakCachingConcurrentResolver(this.getClass()
  25 + .getClassLoader())));
  26 + pipeline.addLast(new ObjectEncoder());
  27 + pipeline.addLast(new SerializationServerHandler());
  28 + }
  29 +}
  1 +/**
  2 + *
  3 + */
  4 +/**
  5 + * 说明:使用 Netty 自带的序列化工具对 Java 对象进行序列化
  6 + *
  7 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月7日
  8 + */
  9 +package com.waylau.netty.demo.codec.serialization;
  1 +package com.waylau.netty.demo.discard;
  2 +
  3 +import io.netty.bootstrap.ServerBootstrap;
  4 +
  5 +import io.netty.channel.ChannelFuture;
  6 +import io.netty.channel.ChannelInitializer;
  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.SocketChannel;
  11 +import io.netty.channel.socket.nio.NioServerSocketChannel;
  12 +
  13 +/**
  14 + * 丢弃任何进入的数据
  15 + */
  16 +public class DiscardServer {
  17 +
  18 + private int port;
  19 +
  20 + public DiscardServer(int port) {
  21 + this.port = port;
  22 + }
  23 +
  24 + public void run() throws Exception {
  25 + EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
  26 + EventLoopGroup workerGroup = new NioEventLoopGroup();
  27 + try {
  28 + ServerBootstrap b = new ServerBootstrap(); // (2)
  29 + b.group(bossGroup, workerGroup)
  30 + .channel(NioServerSocketChannel.class) // (3)
  31 + .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
  32 + @Override
  33 + public void initChannel(SocketChannel ch) throws Exception {
  34 + ch.pipeline().addLast(new DiscardServerHandler());
  35 + }
  36 + })
  37 + .option(ChannelOption.SO_BACKLOG, 128) // (5)
  38 + .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
  39 +
  40 + // 绑定端口,开始接收进来的连接
  41 + ChannelFuture f = b.bind(port).sync(); // (7)
  42 +
  43 + // 等待服务器 socket 关闭 。
  44 + // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。
  45 + f.channel().closeFuture().sync();
  46 + } finally {
  47 + workerGroup.shutdownGracefully();
  48 + bossGroup.shutdownGracefully();
  49 + }
  50 + }
  51 +
  52 + public static void main(String[] args) throws Exception {
  53 + int port;
  54 + if (args.length > 0) {
  55 + port = Integer.parseInt(args[0]);
  56 + } else {
  57 + port = 8080;
  58 + }
  59 + new DiscardServer(port).run();
  60 + }
  61 +}
  1 +package com.waylau.netty.demo.discard;
  2 +
  3 +import io.netty.buffer.ByteBuf;
  4 +import io.netty.channel.ChannelHandlerContext;
  5 +import io.netty.channel.ChannelInboundHandlerAdapter;
  6 +import io.netty.util.ReferenceCountUtil;
  7 +
  8 +/**
  9 + * 处理服务端 channel.
  10 + */
  11 +public class DiscardServerHandler extends ChannelInboundHandlerAdapter { // (1)
  12 +
  13 + @Override
  14 + public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2)
  15 + /*
  16 + // 默默地丢弃收到的数据
  17 + ((ByteBuf) msg).release(); // (3)
  18 + */
  19 +
  20 + /*
  21 + try {
  22 + // Do something with msg
  23 + } finally {
  24 + ReferenceCountUtil.release(msg);
  25 + }
  26 + */
  27 +
  28 + ByteBuf in = (ByteBuf) msg;
  29 + try {
  30 + while (in.isReadable()) { // (1)
  31 + System.out.print((char) in.readByte());
  32 + System.out.flush();
  33 + }
  34 + } finally {
  35 + ReferenceCountUtil.release(msg); // (2)
  36 + }
  37 +
  38 + }
  39 +
  40 + @Override
  41 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4)
  42 + // 当出现异常就关闭连接
  43 + cause.printStackTrace();
  44 + ctx.close();
  45 + }
  46 +}
  1 +package com.waylau.netty.demo.echo;
  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.ChannelPipeline;
  8 +import io.netty.channel.EventLoopGroup;
  9 +import io.netty.channel.nio.NioEventLoopGroup;
  10 +import io.netty.channel.socket.SocketChannel;
  11 +import io.netty.channel.socket.nio.NioSocketChannel;
  12 +import io.netty.handler.codec.DelimiterBasedFrameDecoder;
  13 +import io.netty.handler.codec.Delimiters;
  14 +import io.netty.handler.codec.string.StringDecoder;
  15 +import io.netty.handler.codec.string.StringEncoder;
  16 +
  17 +/**
  18 + * Sends one message when a connection is open and echoes back any received
  19 + * data to the server. Simply put, the echo client initiates the ping-pong
  20 + * traffic between the echo client and server by sending the first message to
  21 + * the server.
  22 + */
  23 +public final class EchoClient {
  24 +
  25 + static final String HOST = System.getProperty("host", "127.0.0.1");
  26 + static final int PORT = Integer.parseInt(System.getProperty("port", "8040"));
  27 +
  28 + public static void main(String[] args) throws Exception {
  29 +
  30 + // Configure the client.
  31 + EventLoopGroup group = new NioEventLoopGroup();
  32 + try {
  33 + Bootstrap b = new Bootstrap();
  34 + b.group(group)
  35 + .channel(NioSocketChannel.class)
  36 + .option(ChannelOption.TCP_NODELAY, true)
  37 + .handler(new ChannelInitializer<SocketChannel>() {
  38 + @Override
  39 + public void initChannel(SocketChannel ch) throws Exception {
  40 + ChannelPipeline p = ch.pipeline();
  41 + p.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
  42 + p.addLast("decoder", new StringDecoder());
  43 + p.addLast("encoder", new StringEncoder());
  44 + p.addLast(new EchoClientHandler());
  45 + }
  46 + });
  47 +
  48 + // Start the client.
  49 + ChannelFuture f = b.connect(HOST, PORT).sync();
  50 +
  51 + // Wait until the connection is closed.
  52 + f.channel().closeFuture().sync();
  53 + } finally {
  54 + // Shut down the event loop to terminate all threads.
  55 + group.shutdownGracefully();
  56 + }
  57 + }
  58 +}
  1 +package com.waylau.netty.demo.echo;
  2 +
  3 +
  4 +
  5 +import io.netty.buffer.ByteBuf;
  6 +import io.netty.buffer.Unpooled;
  7 +import io.netty.channel.ChannelHandlerContext;
  8 +import io.netty.channel.ChannelInboundHandlerAdapter;
  9 +
  10 +public class EchoClientHandler extends ChannelInboundHandlerAdapter {
  11 +
  12 + private final String firstMessage;
  13 +
  14 + /**
  15 + * Creates a client-side handler.
  16 + */
  17 + public EchoClientHandler() {
  18 +// firstMessage = Unpooled.buffer(EchoClient.SIZE);
  19 +// for (int i = 0; i < firstMessage.capacity(); i ++) {
  20 +// firstMessage.writeByte((byte) i);
  21 +// }
  22 +//// firstMessage.writeByte('\n');
  23 + firstMessage = "hello\n";
  24 + }
  25 +
  26 + @Override
  27 + public void channelActive(ChannelHandlerContext ctx) {
  28 + ctx.writeAndFlush(firstMessage);
  29 + System.out.println("channel active.");
  30 + }
  31 +
  32 + @Override
  33 + public void channelRead(ChannelHandlerContext ctx, Object msg) {
  34 + System.out.println("channel read from server: " + msg);
  35 + ctx.write(msg + "\n");
  36 + }
  37 +
  38 + @Override
  39 + public void channelReadComplete(ChannelHandlerContext ctx) {
  40 + ctx.flush();
  41 + System.out.println("channel read complete");
  42 + }
  43 +
  44 + @Override
  45 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  46 + // Close the connection when an exception is raised.
  47 + cause.printStackTrace();
  48 + ctx.close();
  49 + }
  50 + }
  1 +package com.waylau.netty.demo.echo;
  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.DelimiterBasedFrameDecoder;
  12 +import io.netty.handler.codec.Delimiters;
  13 +import io.netty.handler.codec.string.StringDecoder;
  14 +import io.netty.handler.codec.string.StringEncoder;
  15 +
  16 +/**
  17 + * 应答服务器
  18 + */
  19 +public class EchoServer {
  20 +
  21 + private int port;
  22 +
  23 + public EchoServer(int port) {
  24 + this.port = port;
  25 + }
  26 +
  27 + public void run() throws Exception {
  28 + EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
  29 + EventLoopGroup workerGroup = new NioEventLoopGroup();
  30 + try {
  31 + ServerBootstrap b = new ServerBootstrap(); // (2)
  32 + b.group(bossGroup, workerGroup)
  33 + .channel(NioServerSocketChannel.class) // (3)
  34 + .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
  35 + @Override
  36 + public void initChannel(SocketChannel ch) throws Exception {
  37 + ch.pipeline().addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
  38 + ch.pipeline().addLast("decoder", new StringDecoder());
  39 + ch.pipeline().addLast("encoder", new StringEncoder());
  40 + ch.pipeline().addLast(new EchoServerHandler());
  41 + }
  42 + })
  43 + .option(ChannelOption.SO_BACKLOG, 128) // (5)
  44 + .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
  45 +
  46 + // 绑定端口,开始接收进来的连接
  47 + ChannelFuture f = b.bind(port).sync(); // (7)
  48 +
  49 + System.out.println("Server start listen at " + port );
  50 + // 等待服务器 socket 关闭 。
  51 + // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。
  52 + f.channel().closeFuture().sync();
  53 + } finally {
  54 + workerGroup.shutdownGracefully();
  55 + bossGroup.shutdownGracefully();
  56 + }
  57 + }
  58 +
  59 + public static void main(String[] args) throws Exception {
  60 + int port;
  61 + if (args.length > 0) {
  62 + port = Integer.parseInt(args[0]);
  63 + } else {
  64 + port = 8040;
  65 + }
  66 + new EchoServer(port).run();
  67 + }
  68 +}
  1 +package com.waylau.netty.demo.echo;
  2 +
  3 +import io.netty.channel.ChannelFuture;
  4 +import io.netty.channel.ChannelFutureListener;
  5 +import io.netty.channel.ChannelHandlerContext;
  6 +import io.netty.channel.ChannelInboundHandlerAdapter;
  7 +
  8 +import java.util.concurrent.TimeUnit;
  9 +
  10 +/**
  11 + * 处理服务端 channel.
  12 + */
  13 +public class EchoServerHandler extends ChannelInboundHandlerAdapter {
  14 +
  15 + @Override
  16 + public void channelRead(ChannelHandlerContext ctx, Object msg) {
  17 + System.out.println(ctx.channel().remoteAddress()+"->Server :"+ msg.toString());
  18 +// ctx.write(msg); // (1)
  19 +// ctx.flush(); // (2)
  20 +// final ChannelFuture future = ctx.writeAndFlush(msg);
  21 + final ChannelFuture future = ctx.write(msg + "\n");
  22 +// future.addListener(ChannelFutureListener.CLOSE);
  23 +// future.addListener(new ChannelFutureListener() {
  24 +// @Override
  25 +// public void operationComplete(ChannelFuture future) throws Exception {
  26 +// System.out.println("close channel");
  27 +// future.channel().close();
  28 +// }
  29 +// });
  30 + }
  31 +
  32 + @Override
  33 + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  34 + System.out.println("server read complete");
  35 + ctx.flush();
  36 + TimeUnit.MILLISECONDS.sleep(200);
  37 + }
  38 +
  39 + @Override
  40 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  41 + // 当出现异常就关闭连接
  42 + cause.printStackTrace();
  43 + ctx.close();
  44 + }
  45 +}
  1 +package com.waylau.netty.demo.factorial;
  2 +
  3 +import io.netty.buffer.ByteBuf;
  4 +import io.netty.channel.ChannelHandlerContext;
  5 +import io.netty.handler.codec.ByteToMessageDecoder;
  6 +import io.netty.handler.codec.CorruptedFrameException;
  7 +
  8 +import java.math.BigInteger;
  9 +import java.util.List;
  10 +
  11 +/**
  12 + * Decodes the binary representation of a {@link BigInteger} prepended
  13 + * with a magic number ('F' or 0x46) and a 32-bit integer length prefix into a
  14 + * {@link BigInteger} instance. For example, { 'F', 0, 0, 0, 1, 42 } will be
  15 + * decoded into new BigInteger("42").
  16 + */
  17 +public class BigIntegerDecoder extends ByteToMessageDecoder {
  18 +
  19 + @Override
  20 + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
  21 + // Wait until the length prefix is available.
  22 + if (in.readableBytes() < 5) {
  23 + return;
  24 + }
  25 +
  26 + in.markReaderIndex();
  27 +
  28 + // Check the magic number.
  29 + int magicNumber = in.readUnsignedByte();
  30 + if (magicNumber != 'F') {
  31 + in.resetReaderIndex();
  32 + throw new CorruptedFrameException("Invalid magic number: " + magicNumber);
  33 + }
  34 +
  35 + // Wait until the whole data is available.
  36 + int dataLength = in.readInt();
  37 + if (in.readableBytes() < dataLength) {
  38 + in.resetReaderIndex();
  39 + return;
  40 + }
  41 +
  42 + // Convert the received data into a new BigInteger.
  43 + byte[] decoded = new byte[dataLength];
  44 + in.readBytes(decoded);
  45 +
  46 + out.add(new BigInteger(decoded));
  47 + }
  48 +}
  1 +package com.waylau.netty.demo.factorial;
  2 +
  3 +import io.netty.bootstrap.Bootstrap;
  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.NioSocketChannel;
  8 +import io.netty.handler.ssl.SslContext;
  9 +import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
  10 +
  11 +/**
  12 + * Sends a sequence of integers to a {@link FactorialServer} to calculate
  13 + * the factorial of the specified integer.
  14 + */
  15 +public final class FactorialClient {
  16 +
  17 + static final boolean SSL = System.getProperty("ssl") != null;
  18 + static final String HOST = System.getProperty("host", "127.0.0.1");
  19 + static final int PORT = Integer.parseInt(System.getProperty("port", "8322"));
  20 + static final int COUNT = Integer.parseInt(System.getProperty("count", "1000"));
  21 +
  22 + public static void main(String[] args) throws Exception {
  23 + // Configure SSL.
  24 + final SslContext sslCtx;
  25 + if (SSL) {
  26 + sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
  27 + } else {
  28 + sslCtx = null;
  29 + }
  30 +
  31 + EventLoopGroup group = new NioEventLoopGroup();
  32 + try {
  33 + Bootstrap b = new Bootstrap();
  34 + b.group(group)
  35 + .channel(NioSocketChannel.class)
  36 + .handler(new FactorialClientInitializer(sslCtx));
  37 +
  38 + // Make a new connection.
  39 + ChannelFuture f = b.connect(HOST, PORT).sync();
  40 +
  41 + // Get the handler instance to retrieve the answer.
  42 + FactorialClientHandler handler =
  43 + (FactorialClientHandler) f.channel().pipeline().last();
  44 +
  45 + // Print out the answer.
  46 + System.err.format("Factorial of %,d is: %,d", COUNT, handler.getFactorial());
  47 + } finally {
  48 + group.shutdownGracefully();
  49 + }
  50 + }
  51 +}
  1 +package com.waylau.netty.demo.factorial;
  2 +
  3 +import io.netty.channel.ChannelFuture;
  4 +import io.netty.channel.ChannelFutureListener;
  5 +import io.netty.channel.ChannelHandlerContext;
  6 +import io.netty.channel.SimpleChannelInboundHandler;
  7 +
  8 +import java.math.BigInteger;
  9 +import java.util.concurrent.BlockingQueue;
  10 +import java.util.concurrent.LinkedBlockingQueue;
  11 +
  12 +/**
  13 + * Handler for a client-side channel. This handler maintains stateful
  14 + * information which is specific to a certain channel using member variables.
  15 + * Therefore, an instance of this handler can cover only one channel. You have
  16 + * to create a new handler instance whenever you create a new channel and insert
  17 + * this handler to avoid a race condition.
  18 + */
  19 +public class FactorialClientHandler extends SimpleChannelInboundHandler<BigInteger> {
  20 +
  21 + private ChannelHandlerContext ctx;
  22 + private int receivedMessages;
  23 + private int next = 1;
  24 + final BlockingQueue<BigInteger> answer = new LinkedBlockingQueue<BigInteger>();
  25 +
  26 + public BigInteger getFactorial() {
  27 + boolean interrupted = false;
  28 + try {
  29 + for (;;) {
  30 + try {
  31 + return answer.take();
  32 + } catch (InterruptedException ignore) {
  33 + interrupted = true;
  34 + }
  35 + }
  36 + } finally {
  37 + if (interrupted) {
  38 + Thread.currentThread().interrupt();
  39 + }
  40 + }
  41 + }
  42 +
  43 + @Override
  44 + public void channelActive(ChannelHandlerContext ctx) {
  45 + this.ctx = ctx;
  46 + sendNumbers();
  47 + }
  48 +
  49 + public void messageReceived(ChannelHandlerContext ctx, final BigInteger msg) {
  50 + receivedMessages ++;
  51 + if (receivedMessages == FactorialClient.COUNT) {
  52 + // Offer the answer after closing the connection.
  53 + ctx.channel().close().addListener(new ChannelFutureListener() {
  54 + @Override
  55 + public void operationComplete(ChannelFuture future) {
  56 + boolean offered = answer.offer(msg);
  57 + assert offered;
  58 + }
  59 + });
  60 + }
  61 + }
  62 +
  63 + @Override
  64 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  65 + cause.printStackTrace();
  66 + ctx.close();
  67 + }
  68 +
  69 + private void sendNumbers() {
  70 + // Do not send more than 4096 numbers.
  71 + ChannelFuture future = null;
  72 + for (int i = 0; i < 4096 && next <= FactorialClient.COUNT; i++) {
  73 + future = ctx.write(Integer.valueOf(next));
  74 + next++;
  75 + }
  76 + if (next <= FactorialClient.COUNT) {
  77 + assert future != null;
  78 + future.addListener(numberSender);
  79 + }
  80 + ctx.flush();
  81 + }
  82 +
  83 + private final ChannelFutureListener numberSender = new ChannelFutureListener() {
  84 + @Override
  85 + public void operationComplete(ChannelFuture future) throws Exception {
  86 + if (future.isSuccess()) {
  87 + sendNumbers();
  88 + } else {
  89 + future.cause().printStackTrace();
  90 + future.channel().close();
  91 + }
  92 + }
  93 + };
  94 +
  95 + @Override
  96 + protected void channelRead0(ChannelHandlerContext arg0, BigInteger arg1)
  97 + throws Exception {
  98 + // TODO Auto-generated method stub
  99 +
  100 + }
  101 +}
  1 +package com.waylau.netty.demo.factorial;
  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.compression.ZlibCodecFactory;
  7 +import io.netty.handler.codec.compression.ZlibWrapper;
  8 +import io.netty.handler.ssl.SslContext;
  9 +
  10 +/**
  11 + * Creates a newly configured {@link ChannelPipeline} for a client-side channel.
  12 + */
  13 +public class FactorialClientInitializer extends ChannelInitializer<SocketChannel> {
  14 +
  15 + private final SslContext sslCtx;
  16 +
  17 + public FactorialClientInitializer(SslContext sslCtx) {
  18 + this.sslCtx = sslCtx;
  19 + }
  20 +
  21 + @Override
  22 + public void initChannel(SocketChannel ch) {
  23 + ChannelPipeline pipeline = ch.pipeline();
  24 +
  25 + if (sslCtx != null) {
  26 + pipeline.addLast(sslCtx.newHandler(ch.alloc(), FactorialClient.HOST, FactorialClient.PORT));
  27 + }
  28 +
  29 + // Enable stream compression (you can remove these two if unnecessary)
  30 + pipeline.addLast(ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP));
  31 + pipeline.addLast(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
  32 +
  33 + // Add the number codec first,
  34 + pipeline.addLast(new BigIntegerDecoder());
  35 + pipeline.addLast(new NumberEncoder());
  36 +
  37 + // and then business logic.
  38 + pipeline.addLast(new FactorialClientHandler());
  39 + }
  40 +}
  1 +package com.waylau.netty.demo.factorial;
  2 +
  3 +import io.netty.bootstrap.ServerBootstrap;
  4 +import io.netty.channel.EventLoopGroup;
  5 +import io.netty.channel.nio.NioEventLoopGroup;
  6 +import io.netty.channel.socket.nio.NioServerSocketChannel;
  7 +import io.netty.handler.logging.LogLevel;
  8 +import io.netty.handler.logging.LoggingHandler;
  9 +import io.netty.handler.ssl.SslContext;
  10 +import io.netty.handler.ssl.util.SelfSignedCertificate;
  11 +
  12 +/**
  13 + * Receives a sequence of integers from a {@link FactorialClient} to calculate
  14 + * the factorial of the specified integer.
  15 + */
  16 +public final class FactorialServer {
  17 +
  18 + static final boolean SSL = System.getProperty("ssl") != null;
  19 + static final int PORT = Integer.parseInt(System.getProperty("port", "8322"));
  20 +
  21 + public static void main(String[] args) throws Exception {
  22 + // Configure SSL.
  23 + final SslContext sslCtx;
  24 + if (SSL) {
  25 + SelfSignedCertificate ssc = new SelfSignedCertificate();
  26 + sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
  27 + } else {
  28 + sslCtx = null;
  29 + }
  30 +
  31 + EventLoopGroup bossGroup = new NioEventLoopGroup(1);
  32 + EventLoopGroup workerGroup = new NioEventLoopGroup();
  33 + try {
  34 + ServerBootstrap b = new ServerBootstrap();
  35 + b.group(bossGroup, workerGroup)
  36 + .channel(NioServerSocketChannel.class)
  37 + .handler(new LoggingHandler(LogLevel.INFO))
  38 + .childHandler(new FactorialServerInitializer(sslCtx));
  39 +
  40 + b.bind(PORT).sync().channel().closeFuture().sync();
  41 + } finally {
  42 + bossGroup.shutdownGracefully();
  43 + workerGroup.shutdownGracefully();
  44 + }
  45 + }
  46 +}
  1 +package com.waylau.netty.demo.factorial;
  2 +
  3 +import io.netty.channel.ChannelHandlerContext;
  4 +import io.netty.channel.SimpleChannelInboundHandler;
  5 +
  6 +import java.math.BigInteger;
  7 +
  8 +/**
  9 + * Handler for a server-side channel. This handler maintains stateful
  10 + * information which is specific to a certain channel using member variables.
  11 + * Therefore, an instance of this handler can cover only one channel. You have
  12 + * to create a new handler instance whenever you create a new channel and insert
  13 + * this handler to avoid a race condition.
  14 + */
  15 +public class FactorialServerHandler extends SimpleChannelInboundHandler<BigInteger> {
  16 +
  17 + private BigInteger lastMultiplier = new BigInteger("1");
  18 + private BigInteger factorial = new BigInteger("1");
  19 +
  20 + public void messageReceived(ChannelHandlerContext ctx, BigInteger msg) {
  21 + // Calculate the cumulative factorial and send it to the client.
  22 + lastMultiplier = msg;
  23 + factorial = factorial.multiply(msg);
  24 + ctx.writeAndFlush(factorial);
  25 + }
  26 +
  27 + @Override
  28 + public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  29 + System.err.printf("Factorial of %,d is: %,d%n", lastMultiplier, factorial);
  30 + }
  31 +
  32 + @Override
  33 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  34 + cause.printStackTrace();
  35 + ctx.close();
  36 + }
  37 +
  38 + @Override
  39 + protected void channelRead0(ChannelHandlerContext arg0, BigInteger arg1)
  40 + throws Exception {
  41 + // TODO Auto-generated method stub
  42 +
  43 + }
  44 +}
  1 +package com.waylau.netty.demo.factorial;
  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.compression.ZlibCodecFactory;
  7 +import io.netty.handler.codec.compression.ZlibWrapper;
  8 +import io.netty.handler.ssl.SslContext;
  9 +
  10 +/**
  11 + * Creates a newly configured {@link ChannelPipeline} for a server-side channel.
  12 + */
  13 +public class FactorialServerInitializer extends ChannelInitializer<SocketChannel> {
  14 +
  15 + private final SslContext sslCtx;
  16 +
  17 + public FactorialServerInitializer(SslContext sslCtx) {
  18 + this.sslCtx = sslCtx;
  19 + }
  20 +
  21 + @Override
  22 + public void initChannel(SocketChannel ch) {
  23 + ChannelPipeline pipeline = ch.pipeline();
  24 +
  25 + if (sslCtx != null) {
  26 + pipeline.addLast(sslCtx.newHandler(ch.alloc()));
  27 + }
  28 +
  29 + // Enable stream compression (you can remove these two if unnecessary)
  30 + pipeline.addLast(ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP));
  31 + pipeline.addLast(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
  32 +
  33 + // Add the number codec first,
  34 + pipeline.addLast(new BigIntegerDecoder());
  35 + pipeline.addLast(new NumberEncoder());
  36 +
  37 + // and then business logic.
  38 + // Please note we create a handler for every new channel
  39 + // because it has stateful properties.
  40 + pipeline.addLast(new FactorialServerHandler());
  41 + }
  42 +}
  1 +package com.waylau.netty.demo.factorial;
  2 +
  3 +import io.netty.buffer.ByteBuf;
  4 +import io.netty.channel.ChannelHandlerContext;
  5 +import io.netty.handler.codec.MessageToByteEncoder;
  6 +
  7 +import java.math.BigInteger;
  8 +
  9 +/**
  10 + * Encodes a {@link Number} into the binary representation prepended with
  11 + * a magic number ('F' or 0x46) and a 32-bit length prefix. For example, 42
  12 + * will be encoded to { 'F', 0, 0, 0, 1, 42 }.
  13 + */
  14 +public class NumberEncoder extends MessageToByteEncoder<Number> {
  15 +
  16 + @Override
  17 + protected void encode(ChannelHandlerContext ctx, Number msg, ByteBuf out) {
  18 + // Convert to a BigInteger first for easier implementation.
  19 + BigInteger v;
  20 + if (msg instanceof BigInteger) {
  21 + v = (BigInteger) msg;
  22 + } else {
  23 + v = new BigInteger(String.valueOf(msg));
  24 + }
  25 +
  26 + // Convert the number into a byte array.
  27 + byte[] data = v.toByteArray();
  28 + int dataLength = data.length;
  29 +
  30 + // Write a message.
  31 + out.writeByte((byte) 'F'); // magic number
  32 + out.writeInt(dataLength); // data length
  33 + out.writeBytes(data); // data
  34 + }
  35 +}
  1 +/**
  2 + *
  3 + */
  4 +package com.waylau.netty.demo.file;
  5 +
  6 +import java.io.BufferedReader;
  7 +import java.io.IOException;
  8 +import java.io.InputStreamReader;
  9 +
  10 +import io.netty.bootstrap.Bootstrap;
  11 +import io.netty.channel.Channel;
  12 +import io.netty.channel.ChannelFuture;
  13 +import io.netty.channel.ChannelInitializer;
  14 +import io.netty.channel.ChannelOption;
  15 +import io.netty.channel.EventLoopGroup;
  16 +import io.netty.channel.nio.NioEventLoopGroup;
  17 +import io.netty.channel.socket.SocketChannel;
  18 +import io.netty.channel.socket.nio.NioSocketChannel;
  19 +import io.netty.handler.codec.string.StringDecoder;
  20 +import io.netty.handler.codec.string.StringEncoder;
  21 +import io.netty.util.CharsetUtil;
  22 +
  23 +/**
  24 + * 说明:文件客户端
  25 + *
  26 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月6日
  27 + */
  28 +public class FileClient {
  29 +
  30 + private String host;
  31 + private int port;
  32 + private String dest; // 接收到文件存放的路径
  33 +
  34 + /**
  35 + *
  36 + */
  37 + public FileClient(String host, int port, String dest) {
  38 + this.host = host;
  39 + this.port = port;
  40 + this.dest = dest;
  41 + }
  42 +
  43 + public void run() throws InterruptedException, IOException {
  44 +
  45 + EventLoopGroup workerGroup = new NioEventLoopGroup();
  46 +
  47 + try {
  48 + Bootstrap b = new Bootstrap(); // (1)
  49 + b.group(workerGroup); // (2)
  50 + b.channel(NioSocketChannel.class); // (3)
  51 + b.option(ChannelOption.SO_KEEPALIVE, true); // (4)
  52 + b.handler(new ChannelInitializer<SocketChannel>() {
  53 + @Override
  54 + public void initChannel(SocketChannel ch) throws Exception {
  55 + ch.pipeline().addLast("encoder",
  56 + new StringEncoder(CharsetUtil.UTF_8));
  57 + ch.pipeline().addLast("decoder",
  58 + new StringDecoder(CharsetUtil.UTF_8));
  59 + ch.pipeline().addLast(new FileClientHandler(dest));
  60 + }
  61 + });
  62 +
  63 + // 启动客户端
  64 + ChannelFuture f = b.connect(host, port).sync(); // (5)
  65 + Channel channel = f.channel();
  66 +
  67 + // 控制台输入请求的文件路径
  68 + BufferedReader in = new BufferedReader(new InputStreamReader(
  69 + System.in));
  70 + while (true) {
  71 + channel.writeAndFlush(in.readLine() + "\r\n");
  72 + }
  73 +
  74 + // 等待连接关闭
  75 + // f.channel().closeFuture().sync();
  76 + } finally {
  77 + workerGroup.shutdownGracefully();
  78 + }
  79 + }
  80 +
  81 + /**
  82 + * @param args
  83 + * @throws InterruptedException
  84 + */
  85 + public static void main(String[] args) throws InterruptedException, IOException {
  86 + new FileClient("localhost", 8082, "D:/reciveFile.txt").run();
  87 + }
  88 +
  89 +}
  1 +/**
  2 + *
  3 + */
  4 +package com.waylau.netty.demo.file;
  5 +
  6 +import java.io.File;
  7 +import java.io.FileOutputStream;
  8 +
  9 +import io.netty.channel.ChannelHandlerContext;
  10 +import io.netty.channel.SimpleChannelInboundHandler;
  11 +
  12 +/**
  13 + * 说明:文件客户端处理器
  14 + *
  15 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月6日
  16 + */
  17 +public class FileClientHandler extends SimpleChannelInboundHandler<String> {
  18 +
  19 + private String dest;
  20 +
  21 + /**
  22 + *
  23 + * @param dest 文件生成路径
  24 + */
  25 + public FileClientHandler(String dest) {
  26 + this.dest = dest;
  27 + }
  28 +
  29 + @Override
  30 + protected void channelRead0(ChannelHandlerContext ctx, String msg)
  31 + throws Exception {
  32 +
  33 + File file = new File(dest);
  34 + if (!file.exists()) {
  35 + file.createNewFile();
  36 + }
  37 +
  38 + FileOutputStream fos = new FileOutputStream(file);
  39 +
  40 + fos.write(msg.getBytes());
  41 + fos.close();
  42 + }
  43 +
  44 +}
  1 +/*
  2 + * Copyright 2013-2018 Lilinfeng.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * 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,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package com.waylau.netty.demo.file;
  17 +
  18 +import io.netty.bootstrap.ServerBootstrap;
  19 +import io.netty.channel.ChannelFuture;
  20 +import io.netty.channel.ChannelInitializer;
  21 +import io.netty.channel.ChannelOption;
  22 +import io.netty.channel.EventLoopGroup;
  23 +import io.netty.channel.nio.NioEventLoopGroup;
  24 +import io.netty.channel.socket.SocketChannel;
  25 +import io.netty.channel.socket.nio.NioServerSocketChannel;
  26 +import io.netty.handler.codec.LineBasedFrameDecoder;
  27 +import io.netty.handler.codec.string.StringDecoder;
  28 +import io.netty.handler.codec.string.StringEncoder;
  29 +import io.netty.util.CharsetUtil;
  30 +
  31 +/**
  32 + * 说明:文件服务器
  33 + *
  34 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月5日
  35 + */
  36 +public class FileServer {
  37 +
  38 + public void run(int port) throws Exception {
  39 + EventLoopGroup bossGroup = new NioEventLoopGroup();
  40 + EventLoopGroup workerGroup = new NioEventLoopGroup();
  41 + try {
  42 + ServerBootstrap b = new ServerBootstrap();
  43 + b.group(bossGroup, workerGroup)
  44 + .channel(NioServerSocketChannel.class)
  45 + .option(ChannelOption.SO_BACKLOG, 100)
  46 + .childHandler(new ChannelInitializer<SocketChannel>() {
  47 + /*
  48 + * (non-Javadoc)
  49 + *
  50 + * @see
  51 + * io.netty.channel.ChannelInitializer#initChannel(io
  52 + * .netty.channel.Channel)
  53 + */
  54 + public void initChannel(SocketChannel ch)
  55 + throws Exception {
  56 + ch.pipeline().addLast(
  57 + new StringEncoder(CharsetUtil.UTF_8),
  58 + new LineBasedFrameDecoder(1024),
  59 + new StringDecoder(CharsetUtil.UTF_8),
  60 + new FileServerHandler());
  61 + }
  62 + });
  63 + ChannelFuture f = b.bind(port).sync();
  64 + System.out.println("Server start at port : " + port);
  65 + f.channel().closeFuture().sync();
  66 + } finally {
  67 + // 优雅停机
  68 + bossGroup.shutdownGracefully();
  69 + workerGroup.shutdownGracefully();
  70 + }
  71 + }
  72 +
  73 + public static void main(String[] args) throws Exception {
  74 + int port = 8082;
  75 + if (args.length > 0) {
  76 + try {
  77 + port = Integer.parseInt(args[0]);
  78 + } catch (NumberFormatException e) {
  79 + e.printStackTrace();
  80 + }
  81 + }
  82 + new FileServer().run(port);
  83 + }
  84 +}
  1 +/*
  2 + * Copyright 2013-2018 Lilinfeng.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * 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,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package com.waylau.netty.demo.file;
  17 +
  18 +import io.netty.channel.ChannelHandlerContext;
  19 +import io.netty.channel.DefaultFileRegion;
  20 +import io.netty.channel.FileRegion;
  21 +import io.netty.channel.SimpleChannelInboundHandler;
  22 +
  23 +import java.io.File;
  24 +import java.io.RandomAccessFile;
  25 +
  26 +/**
  27 + * 说明:文件服务器处理器
  28 + *
  29 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月5日
  30 + */
  31 +public class FileServerHandler extends SimpleChannelInboundHandler<String> {
  32 +
  33 + private static final String CR = System.getProperty("line.separator");
  34 +
  35 + @Override
  36 + protected void channelRead0(ChannelHandlerContext ctx, String msg)
  37 + throws Exception {
  38 + File file = new File(msg);
  39 + if (file.exists()) {
  40 + if (!file.isFile()) {
  41 + ctx.writeAndFlush("Not a file : " + file + CR);
  42 + return;
  43 + }
  44 + ctx.write(file + " " + file.length() + CR);
  45 + RandomAccessFile randomAccessFile = new RandomAccessFile(msg, "r");
  46 + FileRegion region = new DefaultFileRegion(
  47 + randomAccessFile.getChannel(), 0, randomAccessFile.length());
  48 + ctx.write(region);
  49 + ctx.writeAndFlush(CR);
  50 + randomAccessFile.close();
  51 + } else {
  52 + ctx.writeAndFlush("File not found: " + file + CR);
  53 + }
  54 +
  55 + }
  56 +}
  1 +/**
  2 + *
  3 + */
  4 +/**
  5 + * 说明:本包主要是要演示了文件服务器的功能.
  6 + * 客户端启动时,会指定一个文件要保存的路径,本例为“D:/reciveFile.txt”。
  7 + * 客户端发送文件的请求,需在控制台输入所请求文件的路径(当然为了简单演示,该文件是服务器上的文件),
  8 + * 而后,服务器会将该文件传送给客户端端,客户端将文件内容写入“D:/reciveFile.txt”
  9 + *
  10 + *
  11 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月6日
  12 + */
  13 +package com.waylau.netty.demo.file;
  1 +package com.waylau.netty.demo.heartbeat;
  2 +
  3 +import io.netty.channel.Channel;
  4 +import io.netty.channel.ChannelInitializer;
  5 +import io.netty.channel.ChannelPipeline;
  6 +import io.netty.handler.timeout.IdleStateHandler;
  7 +
  8 +import java.util.concurrent.TimeUnit;
  9 +
  10 +/**
  11 + * 说明:心跳服务器初始化
  12 + *
  13 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月6日
  14 + */
  15 +public class HeartbeatHandlerInitializer extends ChannelInitializer<Channel> {
  16 +
  17 + private static final int READ_IDEL_TIME_OUT = 4; // 读超时
  18 + private static final int WRITE_IDEL_TIME_OUT = 5;// 写超时
  19 + private static final int ALL_IDEL_TIME_OUT = 7; // 所有超时
  20 +
  21 + @Override
  22 + protected void initChannel(Channel ch) throws Exception {
  23 + ChannelPipeline pipeline = ch.pipeline();
  24 + pipeline.addLast(new IdleStateHandler(READ_IDEL_TIME_OUT,
  25 + WRITE_IDEL_TIME_OUT, ALL_IDEL_TIME_OUT, TimeUnit.SECONDS));
  26 + pipeline.addLast(new HeartbeatServerHandler());
  27 + }
  28 +}
  1 +package com.waylau.netty.demo.heartbeat;
  2 +
  3 +import io.netty.bootstrap.ServerBootstrap;
  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.NioServerSocketChannel;
  9 +import io.netty.handler.logging.LogLevel;
  10 +import io.netty.handler.logging.LoggingHandler;
  11 +
  12 +/**
  13 + * 说明:心跳服务器
  14 + *
  15 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月6日
  16 + */
  17 +public final class HeartbeatServer {
  18 +
  19 + static final int PORT = 8082;
  20 +
  21 + public static void main(String[] args) throws Exception {
  22 +
  23 + // Configure the server.
  24 + EventLoopGroup bossGroup = new NioEventLoopGroup(1);
  25 + EventLoopGroup workerGroup = new NioEventLoopGroup();
  26 + try {
  27 + ServerBootstrap b = new ServerBootstrap();
  28 + b.group(bossGroup, workerGroup)
  29 + .channel(NioServerSocketChannel.class)
  30 + .option(ChannelOption.SO_BACKLOG, 100)
  31 + .handler(new LoggingHandler(LogLevel.INFO))
  32 + .childHandler(new HeartbeatHandlerInitializer());
  33 +
  34 + // Start the server.
  35 + ChannelFuture f = b.bind(PORT).sync();
  36 +
  37 + // Wait until the server socket is closed.
  38 + f.channel().closeFuture().sync();
  39 + } finally {
  40 + // Shut down all event loops to terminate all threads.
  41 + bossGroup.shutdownGracefully();
  42 + workerGroup.shutdownGracefully();
  43 + }
  44 + }
  45 +}
  1 +package com.waylau.netty.demo.heartbeat;
  2 +
  3 +import io.netty.buffer.ByteBuf;
  4 +import io.netty.buffer.Unpooled;
  5 +import io.netty.channel.ChannelFutureListener;
  6 +import io.netty.channel.ChannelHandlerContext;
  7 +import io.netty.channel.ChannelInboundHandlerAdapter;
  8 +import io.netty.handler.timeout.IdleState;
  9 +import io.netty.handler.timeout.IdleStateEvent;
  10 +import io.netty.util.CharsetUtil;
  11 +
  12 +/**
  13 + * 说明:心跳服务器处理器
  14 + *
  15 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月6日
  16 + */
  17 +public class HeartbeatServerHandler extends ChannelInboundHandlerAdapter {
  18 +
  19 + // Return a unreleasable view on the given ByteBuf
  20 + // which will just ignore release and retain calls.
  21 + private static final ByteBuf HEARTBEAT_SEQUENCE = Unpooled
  22 + .unreleasableBuffer(Unpooled.copiedBuffer("Heartbeat",
  23 + CharsetUtil.UTF_8));
  24 +
  25 + @Override
  26 + public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
  27 + throws Exception {
  28 +
  29 + if (evt instanceof IdleStateEvent) {
  30 + IdleStateEvent event = (IdleStateEvent) evt;
  31 + String type = "";
  32 + if (event.state() == IdleState.READER_IDLE) {
  33 + type = "read idle";
  34 + } else if (event.state() == IdleState.WRITER_IDLE) {
  35 + type = "write idle";
  36 + } else if (event.state() == IdleState.ALL_IDLE) {
  37 + type = "all idle";
  38 + }
  39 +
  40 + ctx.writeAndFlush(HEARTBEAT_SEQUENCE.duplicate()).addListener(
  41 + ChannelFutureListener.CLOSE_ON_FAILURE);
  42 +
  43 + System.out.println( ctx.channel().remoteAddress()+"超时类型:" + type);
  44 + } else {
  45 + super.userEventTriggered(ctx, evt);
  46 + }
  47 + }
  48 +}
  1 +/**
  2 + *
  3 + */
  4 +/**
  5 + * 说明:本例子是一个心跳服务器程序。
  6 + * 可以设置连接超时时间。如果连接超时,则服务器发送心跳消息给客户端。
  7 + * 本例的客户端可以是 Telnet 程序。
  8 + *
  9 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月6日
  10 + */
  11 +package com.waylau.netty.demo.heartbeat;
  1 +package com.waylau.netty.demo.protocol;
  2 +
  3 +/**
  4 + * 说明:
  5 + *
  6 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月5日
  7 + */
  8 +public class ClientTask implements Runnable {
  9 +
  10 + /**
  11 + *
  12 + */
  13 + public ClientTask() {
  14 + // TODO Auto-generated constructor stub
  15 + }
  16 +
  17 + /* (non-Javadoc)
  18 + * @see java.lang.Runnable#run()
  19 + */
  20 + @Override
  21 + public void run() {
  22 + // TODO Auto-generated method stub
  23 + try {
  24 + ProtocolClient client = new ProtocolClient("localhost", 8082);
  25 +
  26 + client.run();
  27 +
  28 +
  29 + } catch (InterruptedException e) {
  30 + // TODO Auto-generated catch block
  31 + e.printStackTrace();
  32 + }
  33 + }
  34 +
  35 +}
  1 +/**
  2 + *
  3 + */
  4 +package com.waylau.netty.demo.protocol;
  5 +
  6 +/**
  7 + * 说明:消息类型
  8 + *
  9 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月5日
  10 + */
  11 +public enum MsgType {
  12 + EMGW_LOGIN_REQ((byte) 0x00),
  13 + EMGW_LOGIN_RES((byte) 0x01);
  14 +
  15 + private byte value;
  16 +
  17 + public byte getValue() {
  18 + return value;
  19 + }
  20 +
  21 + private MsgType(byte value) {
  22 + this.value = value;
  23 + }
  24 +}
  1 +package com.waylau.netty.demo.protocol;
  2 +
  3 +import java.nio.charset.Charset;
  4 +
  5 +import io.netty.bootstrap.Bootstrap;
  6 +import io.netty.channel.ChannelFuture;
  7 +import io.netty.channel.ChannelInitializer;
  8 +import io.netty.channel.ChannelOption;
  9 +import io.netty.channel.EventLoopGroup;
  10 +import io.netty.channel.nio.NioEventLoopGroup;
  11 +import io.netty.channel.socket.SocketChannel;
  12 +import io.netty.channel.socket.nio.NioSocketChannel;
  13 +
  14 +/**
  15 + * 说明:自定义协议客户端
  16 + *
  17 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月5日
  18 + */
  19 +public class ProtocolClient {
  20 +
  21 + private String host;
  22 + private int port;
  23 +
  24 + private static final int MAX_FRAME_LENGTH = 1024 * 1024;
  25 + private static final int LENGTH_FIELD_LENGTH = 4;
  26 + private static final int LENGTH_FIELD_OFFSET = 6;
  27 + private static final int LENGTH_ADJUSTMENT = 0;
  28 + private static final int INITIAL_BYTES_TO_STRIP = 0;
  29 +
  30 + /**
  31 + *
  32 + */
  33 + public ProtocolClient(String host, int port) {
  34 + this.host = host;
  35 + this.port = port;
  36 + }
  37 +
  38 + public void run() throws InterruptedException {
  39 +
  40 + EventLoopGroup workerGroup = new NioEventLoopGroup();
  41 +
  42 + try {
  43 + Bootstrap b = new Bootstrap(); // (1)
  44 + b.group(workerGroup); // (2)
  45 + b.channel(NioSocketChannel.class); // (3)
  46 + b.option(ChannelOption.SO_KEEPALIVE, true); // (4)
  47 + b.handler(new ChannelInitializer<SocketChannel>() {
  48 + @Override
  49 + public void initChannel(SocketChannel ch) throws Exception {
  50 + ch.pipeline().addLast(
  51 + "decoder",
  52 + new ProtocolDecoder(MAX_FRAME_LENGTH,
  53 + LENGTH_FIELD_OFFSET, LENGTH_FIELD_LENGTH,
  54 + LENGTH_ADJUSTMENT, INITIAL_BYTES_TO_STRIP));
  55 + ch.pipeline().addLast("encoder", new ProtocolEncoder());
  56 + ch.pipeline().addLast(new ProtocolClientHandler());
  57 +
  58 + }
  59 + });
  60 +
  61 + // 启动客户端
  62 + ChannelFuture f = b.connect(host, port).sync(); // (5)
  63 +
  64 + while (true) {
  65 +
  66 + // 发送消息给服务器
  67 + ProtocolMsg msg = new ProtocolMsg();
  68 + ProtocolHeader protocolHeader = new ProtocolHeader();
  69 + protocolHeader.setMagic((byte) 0x01);
  70 + protocolHeader.setMsgType((byte) 0x01);
  71 + protocolHeader.setReserve((short) 0);
  72 + protocolHeader.setSn((short) 0);
  73 + String body = "床前明月光疑是地上霜";
  74 + StringBuffer sb = new StringBuffer();
  75 + for (int i = 0; i < 2700; i++) {
  76 + sb.append(body);
  77 + }
  78 +
  79 + byte[] bodyBytes = sb.toString().getBytes(
  80 + Charset.forName("utf-8"));
  81 + int bodySize = bodyBytes.length;
  82 + protocolHeader.setLen(bodySize);
  83 +
  84 + msg.setProtocolHeader(protocolHeader);
  85 + msg.setBody(sb.toString());
  86 +
  87 + f.channel().writeAndFlush(msg);
  88 + Thread.sleep(2000);
  89 + }
  90 + // 等待连接关闭
  91 + // f.channel().closeFuture().sync();
  92 + } finally {
  93 + workerGroup.shutdownGracefully();
  94 + }
  95 + }
  96 +
  97 + /**
  98 + * @param args
  99 + * @throws InterruptedException
  100 + */
  101 + public static void main(String[] args) throws InterruptedException {
  102 + new ProtocolClient("localhost", 8082).run();
  103 + }
  104 +
  105 +}
  1 +package com.waylau.netty.demo.protocol;
  2 +import io.netty.channel.Channel;
  3 +import io.netty.channel.ChannelHandlerContext;
  4 +import io.netty.channel.SimpleChannelInboundHandler;
  5 +
  6 +/**
  7 + * 说明:处理器
  8 + *
  9 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月7日
  10 + */
  11 +public class ProtocolClientHandler extends SimpleChannelInboundHandler<Object> {
  12 +
  13 +
  14 + @Override
  15 + protected void channelRead0(ChannelHandlerContext ctx, Object obj)
  16 + throws Exception {
  17 + Channel incoming = ctx.channel();
  18 + System.out.println("Server->Client:"+incoming.remoteAddress()+obj.toString());
  19 +
  20 + if(obj instanceof ProtocolMsg) {
  21 + ProtocolMsg msg = (ProtocolMsg)obj;
  22 + System.out.println("Server->Client:"+incoming.remoteAddress()+msg.getBody());
  23 + }
  24 + }
  25 + @Override
  26 + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  27 + //ctx.flush();
  28 + }
  29 +
  30 +}
  1 +/**
  2 + *
  3 + */
  4 +package com.waylau.netty.demo.protocol;
  5 +
  6 +import java.util.concurrent.Executor;
  7 +import java.util.concurrent.Executors;
  8 +
  9 +/**
  10 + * 说明:自定义协议客户端性能测试
  11 + *
  12 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月5日
  13 + */
  14 +public class ProtocolClientTest {
  15 +
  16 + private static final int POOL_SIZE_SEND = 100;
  17 +
  18 + /**
  19 + * @param args
  20 + * @throws InterruptedException
  21 + */
  22 + public static void main(String[] args) throws InterruptedException {
  23 +
  24 + Executor executor = Executors.newFixedThreadPool(POOL_SIZE_SEND);
  25 + for (int i = 0; i < POOL_SIZE_SEND; i++) {
  26 + executor.execute(new ClientTask());
  27 + Thread.sleep(100);
  28 + }
  29 +
  30 + }
  31 +
  32 +}
  1 +package com.waylau.netty.demo.protocol;
  2 +
  3 +import io.netty.buffer.ByteBuf;
  4 +import io.netty.channel.ChannelHandlerContext;
  5 +import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
  6 +
  7 +/**
  8 + * 说明:
  9 + *
  10 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月11日
  11 + */
  12 +public class ProtocolDecoder extends LengthFieldBasedFrameDecoder {
  13 + private static final int HEADER_SIZE = 10;
  14 +
  15 + private byte magic; // 魔数
  16 + private byte msgType; // 消息类型
  17 + private short reserve; // 保留字
  18 + private short sn; // 序列号
  19 + private int len; // 长度
  20 +
  21 + /**
  22 + * @param maxFrameLength
  23 + * @param lengthFieldOffset
  24 + * @param lengthFieldLength
  25 + * @param lengthAdjustment
  26 + * @param initialBytesToStrip
  27 + */
  28 + public ProtocolDecoder(int maxFrameLength, int lengthFieldOffset,
  29 + int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) {
  30 + super(maxFrameLength, lengthFieldOffset, lengthFieldLength,
  31 + lengthAdjustment, initialBytesToStrip);
  32 + }
  33 +
  34 + /**
  35 + * @param maxFrameLength
  36 + * @param lengthFieldOffset
  37 + * @param lengthFieldLength
  38 + * @param lengthAdjustment
  39 + * @param initialBytesToStrip
  40 + * @param failFast
  41 + */
  42 + public ProtocolDecoder(int maxFrameLength, int lengthFieldOffset,
  43 + int lengthFieldLength, int lengthAdjustment,
  44 + int initialBytesToStrip, boolean failFast) {
  45 + super(maxFrameLength, lengthFieldOffset, lengthFieldLength,
  46 + lengthAdjustment, initialBytesToStrip, failFast);
  47 + // TODO Auto-generated constructor stub
  48 + }
  49 +
  50 +
  51 + @Override
  52 + protected ProtocolMsg decode(ChannelHandlerContext ctx, ByteBuf in2) throws Exception {
  53 + ByteBuf in = (ByteBuf) super.decode(ctx, in2);
  54 + if (in == null) {
  55 + return null;
  56 + }
  57 +
  58 + if (in.readableBytes() < HEADER_SIZE) {
  59 + return null;// response header is 10 bytes
  60 + }
  61 +
  62 + magic = in.readByte();
  63 + msgType = in.readByte();
  64 + reserve = in.readShort();
  65 + sn = in.readShort();
  66 + len = in.readInt();
  67 +
  68 + if (in.readableBytes() < len) {
  69 + return null; // until we have the entire payload return
  70 + }
  71 +
  72 + ByteBuf buf = in.readBytes(len);
  73 + byte[] req = new byte[buf.readableBytes()];
  74 + buf.readBytes(req);
  75 + String body = new String(req, "UTF-8");
  76 + ProtocolMsg msg = new ProtocolMsg();
  77 + ProtocolHeader protocolHeader = new ProtocolHeader(magic, msgType,
  78 + reserve, sn, len);
  79 + msg.setBody(body);
  80 + msg.setProtocolHeader(protocolHeader);
  81 + return msg;
  82 + }
  83 +}
  1 +/**
  2 + *
  3 + */
  4 +package com.waylau.netty.demo.protocol;
  5 +
  6 +import java.util.List;
  7 +
  8 +import io.netty.buffer.ByteBuf;
  9 +import io.netty.channel.ChannelHandlerContext;
  10 +import io.netty.handler.codec.ByteToMessageDecoder;
  11 +
  12 +/**
  13 + * 说明:
  14 + *
  15 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月10日
  16 + */
  17 +public class ProtocolDecoderDeprecation extends ByteToMessageDecoder {
  18 +
  19 + private static final int HEADER_SIZE = 10;
  20 +
  21 + private byte magic; // 魔数
  22 + private byte msgType; // 消息类型
  23 + private short reserve; // 保留字
  24 + private short sn; // 序列号
  25 + private int len; // 长度
  26 +
  27 + /**
  28 + *
  29 + */
  30 + public ProtocolDecoderDeprecation() {
  31 + // TODO Auto-generated constructor stub
  32 + }
  33 +
  34 + /*
  35 + * (non-Javadoc)
  36 + *
  37 + * @see io.netty.handler.codec.ByteToMessageDecoder#decode(io.netty.channel.
  38 + * ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List)
  39 + */
  40 + @Override
  41 + protected void decode(ChannelHandlerContext ctx, ByteBuf in,
  42 + List<Object> out) throws Exception {
  43 + if (in.readableBytes() < HEADER_SIZE) {
  44 + return;// response header is 10 bytes
  45 + }
  46 +
  47 + magic = in.readByte();
  48 + msgType = in.readByte();
  49 + reserve = in.readShort();
  50 + sn = in.readShort();
  51 + len = in.readInt();
  52 +
  53 + if (in.readableBytes() < len) {
  54 + return; // until we have the entire payload return
  55 + }
  56 +
  57 + ByteBuf buf = in.readBytes(len);
  58 + byte[] req = new byte[buf.readableBytes()];
  59 + buf.readBytes(req);
  60 + String body = new String(req, "UTF-8");
  61 + ProtocolMsg msg = new ProtocolMsg();
  62 +
  63 +// ProtocolBody body2 = new ProtocolBody();
  64 +// body2.setBody(body);
  65 + ProtocolHeader protocolHeader = new ProtocolHeader(magic, msgType,
  66 + reserve, sn, len);
  67 + //msg.setProtocolBody(body2);
  68 + msg.setBody(body);
  69 + msg.setProtocolHeader(protocolHeader);
  70 + out.add(msg);
  71 +
  72 + }
  73 +
  74 +}
  1 +/**
  2 + *
  3 + */
  4 +package com.waylau.netty.demo.protocol;
  5 +
  6 +import java.nio.charset.Charset;
  7 +
  8 +
  9 +import io.netty.buffer.ByteBuf;
  10 +import io.netty.channel.ChannelHandlerContext;
  11 +import io.netty.handler.codec.MessageToByteEncoder;
  12 +
  13 +/**
  14 + * 说明:编码器
  15 + *
  16 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月10日
  17 + */
  18 +public class ProtocolEncoder extends MessageToByteEncoder<ProtocolMsg> {
  19 +
  20 + /**
  21 + *
  22 + */
  23 + public ProtocolEncoder() {
  24 + // TODO Auto-generated constructor stub
  25 + }
  26 +
  27 + /**
  28 + * @param outboundMessageType
  29 + */
  30 + public ProtocolEncoder(Class<? extends ProtocolMsg> outboundMessageType) {
  31 + super(outboundMessageType);
  32 + // TODO Auto-generated constructor stub
  33 + }
  34 +
  35 + /**
  36 + * @param preferDirect
  37 + */
  38 + public ProtocolEncoder(boolean preferDirect) {
  39 + super(preferDirect);
  40 + // TODO Auto-generated constructor stub
  41 + }
  42 +
  43 + /**
  44 + * @param outboundMessageType
  45 + * @param preferDirect
  46 + */
  47 + public ProtocolEncoder(Class<? extends ProtocolMsg> outboundMessageType,
  48 + boolean preferDirect) {
  49 + super(outboundMessageType, preferDirect);
  50 + // TODO Auto-generated constructor stub
  51 + }
  52 +
  53 + /* (non-Javadoc)
  54 + * @see io.netty.handler.codec.MessageToByteEncoder#encode(io.netty.channel.ChannelHandlerContext, java.lang.Object, io.netty.buffer.ByteBuf)
  55 + */
  56 + @Override
  57 + protected void encode(ChannelHandlerContext ctx, ProtocolMsg msg,
  58 + ByteBuf out) throws Exception {
  59 + if (msg == null | msg.getProtocolHeader() == null) {
  60 + throw new Exception("The encode message is null");
  61 + }
  62 + ProtocolHeader header = msg.getProtocolHeader();
  63 + String body = msg.getBody();
  64 + byte[] bodyBytes = body.getBytes(Charset.forName("utf-8"));
  65 + int bodySize = bodyBytes.length;
  66 +
  67 + out.writeByte(header.getMagic());
  68 + out.writeByte(header.getMsgType());
  69 + out.writeShort(header.getReserve());
  70 + out.writeShort(header.getSn());
  71 + out.writeInt(bodySize);
  72 + out.writeBytes(bodyBytes);
  73 + }
  74 +
  75 +}
  1 +package com.waylau.netty.demo.protocol;
  2 +
  3 +
  4 +/**
  5 + * 说明:协议消息头
  6 + *
  7 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月4日
  8 + */
  9 +public class ProtocolHeader{
  10 +
  11 + private byte magic; // 魔数
  12 + private byte msgType; // 消息类型
  13 + private short reserve; // 保留字
  14 + private short sn; // 序列号
  15 + private int len; // 长度
  16 +
  17 + public byte getMagic() {
  18 + return magic;
  19 + }
  20 + public void setMagic(byte magic) {
  21 + this.magic = magic;
  22 + }
  23 + public byte getMsgType() {
  24 + return msgType;
  25 + }
  26 + public void setMsgType(byte msgType) {
  27 + this.msgType = msgType;
  28 + }
  29 + public short getReserve() {
  30 + return reserve;
  31 + }
  32 + public void setReserve(short reserve) {
  33 + this.reserve = reserve;
  34 + }
  35 + public short getSn() {
  36 + return sn;
  37 + }
  38 + public void setSn(short sn) {
  39 + this.sn = sn;
  40 + }
  41 + public int getLen() {
  42 + return len;
  43 + }
  44 + public void setLen(int len) {
  45 + this.len = len;
  46 + }
  47 + public ProtocolHeader() {
  48 + }
  49 + /**
  50 + *
  51 + */
  52 + public ProtocolHeader(byte magic, byte msgType,short reserve,short sn,int len) {
  53 + this.magic = magic;
  54 + this.msgType = msgType;
  55 + this.reserve = reserve;
  56 + this.sn = sn;
  57 + this.len = len;
  58 + }
  59 +
  60 +}
  1 +package com.waylau.netty.demo.protocol;
  2 +
  3 +/**
  4 + * 说明:消息对象
  5 + *
  6 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月5日
  7 + */
  8 +public class ProtocolMsg {
  9 +
  10 + private ProtocolHeader protocolHeader = new ProtocolHeader();
  11 + private String body;
  12 +
  13 + public String getBody() {
  14 + return body;
  15 + }
  16 +
  17 + public void setBody(String body) {
  18 + this.body = body;
  19 + }
  20 +
  21 +
  22 + /**
  23 + *
  24 + */
  25 + public ProtocolMsg() {
  26 + // TODO Auto-generated constructor stub
  27 + }
  28 +
  29 + public ProtocolHeader getProtocolHeader() {
  30 + return protocolHeader;
  31 + }
  32 +
  33 + public void setProtocolHeader(ProtocolHeader protocolHeader) {
  34 + this.protocolHeader = protocolHeader;
  35 + }
  36 +
  37 +
  38 +}
  1 +/**
  2 + *
  3 + */
  4 +package com.waylau.netty.demo.protocol;
  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 +
  15 +/**
  16 + * 说明:自定义协议服务端
  17 + *
  18 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月5日
  19 + */
  20 +public class ProtocolServer {
  21 +
  22 + private int port;
  23 +
  24 + private static final int MAX_FRAME_LENGTH = 1024 * 1024;
  25 + private static final int LENGTH_FIELD_LENGTH = 4;
  26 + private static final int LENGTH_FIELD_OFFSET = 6;
  27 + private static final int LENGTH_ADJUSTMENT = 0;
  28 + private static final int INITIAL_BYTES_TO_STRIP = 0;
  29 +
  30 + /**
  31 + *
  32 + */
  33 + public ProtocolServer(int port) {
  34 + this.port = port;
  35 + }
  36 +
  37 + public void run() throws Exception {
  38 + EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
  39 + EventLoopGroup workerGroup = new NioEventLoopGroup();
  40 + try {
  41 + ServerBootstrap b = new ServerBootstrap(); // (2)
  42 + b.group(bossGroup, workerGroup)
  43 + .channel(NioServerSocketChannel.class) // (3)
  44 + .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
  45 + @Override
  46 + public void initChannel(SocketChannel ch) throws Exception {
  47 + ch.pipeline().addLast("decoder",
  48 + new ProtocolDecoder(MAX_FRAME_LENGTH,
  49 + LENGTH_FIELD_OFFSET,LENGTH_FIELD_LENGTH,
  50 + LENGTH_ADJUSTMENT, INITIAL_BYTES_TO_STRIP));
  51 + ch.pipeline().addLast("encoder", new ProtocolEncoder());
  52 + ch.pipeline().addLast(new ProtocolServerHandler());
  53 + }
  54 + })
  55 + .option(ChannelOption.SO_BACKLOG, 128) // (5)
  56 + .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
  57 +
  58 + // 绑定端口,开始接收进来的连接
  59 + ChannelFuture f = b.bind(port).sync(); // (7)
  60 +
  61 + System.out.println("Server start listen at " + port );
  62 +
  63 + // 等待服务器 socket 关闭 。
  64 + // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。
  65 + f.channel().closeFuture().sync();
  66 +
  67 +
  68 + } finally {
  69 + workerGroup.shutdownGracefully();
  70 + bossGroup.shutdownGracefully();
  71 + }
  72 + }
  73 + /**
  74 + * @param args
  75 + * @throws Exception
  76 + */
  77 + public static void main(String[] args) throws Exception {
  78 + int port;
  79 + if (args.length > 0) {
  80 + port = Integer.parseInt(args[0]);
  81 + } else {
  82 + port = 8082;
  83 + }
  84 + new ProtocolServer(port).run();
  85 + }
  86 +
  87 +}
  1 +package com.waylau.netty.demo.protocol;
  2 +
  3 +import io.netty.channel.Channel;
  4 +import io.netty.channel.ChannelHandlerContext;
  5 +import io.netty.channel.SimpleChannelInboundHandler;
  6 +
  7 +/**
  8 + * 说明:处理器
  9 + *
  10 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月7日
  11 + */
  12 +public class ProtocolServerHandler extends SimpleChannelInboundHandler<Object> {
  13 +
  14 +
  15 + @Override
  16 + protected void channelRead0(ChannelHandlerContext ctx, Object obj)
  17 + throws Exception {
  18 + Channel incoming = ctx.channel();
  19 +
  20 + if(obj instanceof ProtocolMsg) {
  21 + ProtocolMsg msg = (ProtocolMsg)obj;
  22 + System.out.println("Client->Server:"+incoming.remoteAddress()+msg.getBody());
  23 + incoming.write(obj);
  24 + }
  25 + }
  26 +
  27 + @Override
  28 + public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  29 + ctx.flush();
  30 + }
  31 +}
  1 +/**
  2 + * 说明:该包下的例子,主要是实现了自定义二进制协议
  3 + *
  4 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月4日
  5 + */
  6 +package com.waylau.netty.demo.protocol;
  1 +## 消息格式
  2 +
  3 +类型 | 名称 | 字节序列 | 取值范围 | 备注
  4 +--- | ----- | ---------| --------- |----
  5 +消息头 | magic | 0 |0x80、0x81 |帧头
  6 + | msgType | 1 |0x00-0xff |消息类型
  7 + | reserve | 2-3 |0x00 |保留字,以备扩展
  8 + | sn |4-5 |0-32767 |序列号。是一个事务标识,从0开始,每次递增1,响应消息中的序列号是从请求消息中拷贝来的。当序列号达到最大值时(32767),则又从0开始。
  9 + | len |6-9 |0-2147483647 |消息体长度。
  10 +消息体 | body |变长 |0- |消息体。格式和消息类型相关,不同的消息类型有不同的消息体格式。消息大小不应超过2G
  11 +
  12 +
  1 +package com.waylau.netty.demo.securechat;
  2 +
  3 +import io.netty.bootstrap.Bootstrap;
  4 +import io.netty.channel.Channel;
  5 +import io.netty.channel.ChannelFuture;
  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.ssl.SslContext;
  10 +import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
  11 +
  12 +import java.io.BufferedReader;
  13 +import java.io.InputStreamReader;
  14 +
  15 +/**
  16 + * Simple SSL chat client
  17 + */
  18 +public final class SecureChatClient {
  19 +
  20 + static final String HOST = System.getProperty("host", "127.0.0.1");
  21 + static final int PORT = Integer.parseInt(System.getProperty("port", "8992"));
  22 +
  23 + public static void main(String[] args) throws Exception {
  24 + // Configure SSL.
  25 + final SslContext sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
  26 +
  27 + EventLoopGroup group = new NioEventLoopGroup();
  28 + try {
  29 + Bootstrap b = new Bootstrap();
  30 + b.group(group)
  31 + .channel(NioSocketChannel.class)
  32 + .handler(new SecureChatClientInitializer(sslCtx));
  33 +
  34 + // Start the connection attempt.
  35 + Channel ch = b.connect(HOST, PORT).sync().channel();
  36 +
  37 + // Read commands from the stdin.
  38 + ChannelFuture lastWriteFuture = null;
  39 + BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
  40 + for (;;) {
  41 + String line = in.readLine();
  42 + if (line == null) {
  43 + break;
  44 + }
  45 +
  46 + // Sends the received line to the server.
  47 + lastWriteFuture = ch.writeAndFlush(line + "\r\n");
  48 +
  49 + // If user typed the 'bye' command, wait until the server closes
  50 + // the connection.
  51 + if ("bye".equals(line.toLowerCase())) {
  52 + ch.closeFuture().sync();
  53 + break;
  54 + }
  55 + }
  56 +
  57 + // Wait until all messages are flushed before closing the channel.
  58 + if (lastWriteFuture != null) {
  59 + lastWriteFuture.sync();
  60 + }
  61 + } finally {
  62 + // The connection is closed automatically on shutdown.
  63 + group.shutdownGracefully();
  64 + }
  65 + }
  66 +}
  1 +package com.waylau.netty.demo.securechat;
  2 +
  3 +import io.netty.channel.ChannelHandlerContext;
  4 +import io.netty.channel.SimpleChannelInboundHandler;
  5 +
  6 +/**
  7 + * Handles a client-side channel.
  8 + */
  9 +public class SecureChatClientHandler extends SimpleChannelInboundHandler<String> {
  10 +
  11 + public void messageReceived(ChannelHandlerContext ctx, String msg) {
  12 + System.err.println(msg);
  13 + }
  14 +
  15 + @Override
  16 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  17 + cause.printStackTrace();
  18 + ctx.close();
  19 + }
  20 +
  21 + @Override
  22 + protected void channelRead0(ChannelHandlerContext ctx, String msg)
  23 + throws Exception {
  24 + // TODO Auto-generated method stub
  25 +
  26 + }
  27 +}
  1 +package com.waylau.netty.demo.securechat;
  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 +import io.netty.handler.ssl.SslContext;
  11 +
  12 +/**
  13 + * Creates a newly configured {@link ChannelPipeline} for a new channel.
  14 + */
  15 +public class SecureChatClientInitializer extends ChannelInitializer<SocketChannel> {
  16 +
  17 + private final SslContext sslCtx;
  18 +
  19 + public SecureChatClientInitializer(SslContext sslCtx) {
  20 + this.sslCtx = sslCtx;
  21 + }
  22 +
  23 + @Override
  24 + public void initChannel(SocketChannel ch) throws Exception {
  25 + ChannelPipeline pipeline = ch.pipeline();
  26 +
  27 + // Add SSL handler first to encrypt and decrypt everything.
  28 + // In this example, we use a bogus certificate in the server side
  29 + // and accept any invalid certificates in the client side.
  30 + // You will need something more complicated to identify both
  31 + // and server in the real world.
  32 + pipeline.addLast(sslCtx.newHandler(ch.alloc(), SecureChatClient.HOST, SecureChatClient.PORT));
  33 +
  34 + // On top of the SSL handler, add the text line codec.
  35 + pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
  36 + pipeline.addLast(new StringDecoder());
  37 + pipeline.addLast(new StringEncoder());
  38 +
  39 + // and then business logic.
  40 + pipeline.addLast(new SecureChatClientHandler());
  41 + }
  42 +}
  1 +package com.waylau.netty.demo.securechat;
  2 +
  3 +import io.netty.bootstrap.ServerBootstrap;
  4 +import io.netty.channel.EventLoopGroup;
  5 +import io.netty.channel.nio.NioEventLoopGroup;
  6 +import io.netty.channel.socket.nio.NioServerSocketChannel;
  7 +import io.netty.handler.logging.LogLevel;
  8 +import io.netty.handler.logging.LoggingHandler;
  9 +import io.netty.handler.ssl.SslContext;
  10 +import io.netty.handler.ssl.util.SelfSignedCertificate;
  11 +
  12 +/**
  13 + * Simple SSL chat server
  14 + */
  15 +public final class SecureChatServer {
  16 +
  17 + static final int PORT = Integer.parseInt(System.getProperty("port", "8992"));
  18 +
  19 + public static void main(String[] args) throws Exception {
  20 + SelfSignedCertificate ssc = new SelfSignedCertificate();
  21 + SslContext sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
  22 +
  23 + EventLoopGroup bossGroup = new NioEventLoopGroup(1);
  24 + EventLoopGroup workerGroup = new NioEventLoopGroup();
  25 + try {
  26 + ServerBootstrap b = new ServerBootstrap();
  27 + b.group(bossGroup, workerGroup)
  28 + .channel(NioServerSocketChannel.class)
  29 + .handler(new LoggingHandler(LogLevel.INFO))
  30 + .childHandler(new SecureChatServerInitializer(sslCtx));
  31 +
  32 + b.bind(PORT).sync().channel().closeFuture().sync();
  33 + } finally {
  34 + bossGroup.shutdownGracefully();
  35 + workerGroup.shutdownGracefully();
  36 + }
  37 + }
  38 +}
  1 +package com.waylau.netty.demo.securechat;
  2 +
  3 +import io.netty.channel.Channel;
  4 +import io.netty.channel.ChannelHandlerContext;
  5 +import io.netty.channel.SimpleChannelInboundHandler;
  6 +import io.netty.channel.group.ChannelGroup;
  7 +import io.netty.channel.group.DefaultChannelGroup;
  8 +import io.netty.handler.ssl.SslHandler;
  9 +import io.netty.util.concurrent.Future;
  10 +import io.netty.util.concurrent.GenericFutureListener;
  11 +import io.netty.util.concurrent.GlobalEventExecutor;
  12 +
  13 +import java.net.InetAddress;
  14 +
  15 +/**
  16 + * Handles a server-side channel.
  17 + */
  18 +public class SecureChatServerHandler extends SimpleChannelInboundHandler<String> {
  19 +
  20 + static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
  21 +
  22 + @Override
  23 + public void channelActive(final ChannelHandlerContext ctx) {
  24 + // Once session is secured, send a greeting and register the channel to the global channel
  25 + // list so the channel received the messages from others.
  26 + ctx.pipeline().get(SslHandler.class).handshakeFuture().addListener(
  27 + new GenericFutureListener<Future<Channel>>() {
  28 + @Override
  29 + public void operationComplete(Future<Channel> future) throws Exception {
  30 + ctx.writeAndFlush(
  31 + "Welcome to " + InetAddress.getLocalHost().getHostName() + " secure chat service!\n");
  32 + ctx.writeAndFlush(
  33 + "Your session is protected by " +
  34 + ctx.pipeline().get(SslHandler.class).engine().getSession().getCipherSuite() +
  35 + " cipher suite.\n");
  36 +
  37 + channels.add(ctx.channel());
  38 + }
  39 + });
  40 + }
  41 +
  42 + public void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
  43 + // Send the received message to all channels but the current one.
  44 + for (Channel c: channels) {
  45 + if (c != ctx.channel()) {
  46 + c.writeAndFlush("[" + ctx.channel().remoteAddress() + "] " + msg + '\n');
  47 + } else {
  48 + c.writeAndFlush("[you] " + msg + '\n');
  49 + }
  50 + }
  51 +
  52 + // Close the connection if the client has sent 'bye'.
  53 + if ("bye".equals(msg.toLowerCase())) {
  54 + ctx.close();
  55 + }
  56 + }
  57 +
  58 + @Override
  59 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  60 + cause.printStackTrace();
  61 + ctx.close();
  62 + }
  63 +
  64 + @Override
  65 + protected void channelRead0(ChannelHandlerContext ctx, String msg)
  66 + throws Exception {
  67 + // TODO Auto-generated method stub
  68 +
  69 + }
  70 +}
  1 +package com.waylau.netty.demo.securechat;
  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 +import io.netty.handler.ssl.SslContext;
  11 +
  12 +/**
  13 + * Creates a newly configured {@link ChannelPipeline} for a new channel.
  14 + */
  15 +public class SecureChatServerInitializer extends ChannelInitializer<SocketChannel> {
  16 +
  17 + private final SslContext sslCtx;
  18 +
  19 + public SecureChatServerInitializer(SslContext sslCtx) {
  20 + this.sslCtx = sslCtx;
  21 + }
  22 +
  23 + @Override
  24 + public void initChannel(SocketChannel ch) throws Exception {
  25 + ChannelPipeline pipeline = ch.pipeline();
  26 +
  27 + // Add SSL handler first to encrypt and decrypt everything.
  28 + // In this example, we use a bogus certificate in the server side
  29 + // and accept any invalid certificates in the client side.
  30 + // You will need something more complicated to identify both
  31 + // and server in the real world.
  32 + pipeline.addLast(sslCtx.newHandler(ch.alloc()));
  33 +
  34 + // On top of the SSL handler, add the text line codec.
  35 + pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
  36 + pipeline.addLast(new StringDecoder());
  37 + pipeline.addLast(new StringEncoder());
  38 +
  39 + // and then business logic.
  40 + pipeline.addLast(new SecureChatServerHandler());
  41 + }
  42 +}
  1 +package com.waylau.netty.demo.simplechat;
  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.InputStreamReader;
  11 +
  12 +
  13 +/**
  14 + * 简单聊天服务器-客户端
  15 + *
  16 + * @author waylau.com
  17 + * @date 2015-2-26
  18 + */
  19 +public class SimpleChatClient {
  20 +
  21 + public static void main(String[] args) throws Exception{
  22 + new SimpleChatClient("localhost", 8080).run();
  23 + }
  24 +
  25 + private final String host;
  26 + private final int port;
  27 +
  28 + public SimpleChatClient(String host, int port){
  29 + this.host = host;
  30 + this.port = port;
  31 + }
  32 +
  33 + public void run() throws Exception{
  34 + EventLoopGroup group = new NioEventLoopGroup();
  35 + try {
  36 + Bootstrap bootstrap = new Bootstrap()
  37 + .group(group)
  38 + .channel(NioSocketChannel.class)
  39 + .handler(new SimpleChatClientInitializer());
  40 + Channel channel = bootstrap.connect(host, port).sync().channel();
  41 + BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
  42 + while(true){
  43 + channel.writeAndFlush(in.readLine() + "\r\n");
  44 + }
  45 + } catch (Exception e) {
  46 + e.printStackTrace();
  47 + } finally {
  48 + group.shutdownGracefully();
  49 + }
  50 +
  51 + }
  52 +
  53 +}
  1 +package com.waylau.netty.demo.simplechat;
  2 +
  3 +import io.netty.channel.ChannelHandlerContext;
  4 +import io.netty.channel.SimpleChannelInboundHandler;
  5 +
  6 +/**
  7 + * 客户端 channel
  8 + *
  9 + * @author waylau.com
  10 + * @date 2015-2-26
  11 + */
  12 +public class SimpleChatClientHandler extends SimpleChannelInboundHandler<String> {
  13 + @Override
  14 + protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception {
  15 + System.out.println(s);
  16 + }
  17 +}
  1 +package com.waylau.netty.demo.simplechat;
  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 +/**
  13 + * 客户端 ChannelInitializer
  14 + *
  15 + * @author waylau.com
  16 + * @date 2015-2-26
  17 + */
  18 +public class SimpleChatClientInitializer extends ChannelInitializer<SocketChannel> {
  19 +
  20 + @Override
  21 + public void initChannel(SocketChannel ch) throws Exception {
  22 + ChannelPipeline pipeline = ch.pipeline();
  23 +
  24 + pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
  25 + pipeline.addLast("decoder", new StringDecoder());
  26 + pipeline.addLast("encoder", new StringEncoder());
  27 + pipeline.addLast("handler", new SimpleChatClientHandler());
  28 + }
  29 +}
  1 +package com.waylau.netty.demo.simplechat;
  2 +
  3 +import io.netty.bootstrap.ServerBootstrap;
  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.NioServerSocketChannel;
  9 +
  10 +/**
  11 + * 简单聊天服务器-服务端
  12 + *
  13 + * @author waylau.com
  14 + * @date 2015-2-16
  15 + */
  16 +public class SimpleChatServer {
  17 +
  18 + private int port;
  19 +
  20 + public SimpleChatServer(int port) {
  21 + this.port = port;
  22 + }
  23 +
  24 + public void run() throws Exception {
  25 +
  26 + EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
  27 + EventLoopGroup workerGroup = new NioEventLoopGroup();
  28 + try {
  29 + ServerBootstrap b = new ServerBootstrap(); // (2)
  30 + b.group(bossGroup, workerGroup)
  31 + .channel(NioServerSocketChannel.class) // (3)
  32 + .childHandler(new SimpleChatServerInitializer()) //(4)
  33 + .option(ChannelOption.SO_BACKLOG, 128) // (5)
  34 + .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
  35 +
  36 + System.out.println("SimpleChatServer 启动了");
  37 +
  38 + // 绑定端口,开始接收进来的连接
  39 + ChannelFuture f = b.bind(port).sync(); // (7)
  40 +
  41 + // 等待服务器 socket 关闭 。
  42 + // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。
  43 + f.channel().closeFuture().sync();
  44 +
  45 + } finally {
  46 + workerGroup.shutdownGracefully();
  47 + bossGroup.shutdownGracefully();
  48 +
  49 + System.out.println("SimpleChatServer 关闭了");
  50 + }
  51 + }
  52 +
  53 + public static void main(String[] args) throws Exception {
  54 + int port;
  55 + if (args.length > 0) {
  56 + port = Integer.parseInt(args[0]);
  57 + } else {
  58 + port = 8080;
  59 + }
  60 + new SimpleChatServer(port).run();
  61 +
  62 + }
  63 +}
  1 +package com.waylau.netty.demo.simplechat;
  2 +
  3 +import io.netty.channel.Channel;
  4 +import io.netty.channel.ChannelHandlerContext;
  5 +import io.netty.channel.SimpleChannelInboundHandler;
  6 +import io.netty.channel.group.ChannelGroup;
  7 +import io.netty.channel.group.DefaultChannelGroup;
  8 +import io.netty.util.concurrent.GlobalEventExecutor;
  9 +
  10 +/**
  11 + * 服务端 channel
  12 + *
  13 + * @author waylau.com
  14 + * @date 2015-2-16
  15 + */
  16 +public class SimpleChatServerHandler extends SimpleChannelInboundHandler<String> { // (1)
  17 +
  18 + /**
  19 + * A thread-safe Set Using ChannelGroup, you can categorize Channels into a meaningful group.
  20 + * A closed Channel is automatically removed from the collection,
  21 + */
  22 + public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
  23 +
  24 + @Override
  25 + public void handlerAdded(ChannelHandlerContext ctx) throws Exception { // (2)
  26 + Channel incoming = ctx.channel();
  27 +
  28 + // Broadcast a message to multiple Channels
  29 + channels.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 加入\n");
  30 +
  31 + channels.add(ctx.channel());
  32 + }
  33 +
  34 + @Override
  35 + public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { // (3)
  36 + Channel incoming = ctx.channel();
  37 +
  38 + // Broadcast a message to multiple Channels
  39 + channels.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 离开\n");
  40 +
  41 + // A closed Channel is automatically removed from ChannelGroup,
  42 + // so there is no need to do "channels.remove(ctx.channel());"
  43 + }
  44 + @Override
  45 + protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception { // (4)
  46 + Channel incoming = ctx.channel();
  47 + for (Channel channel : channels) {
  48 + if (channel != incoming){
  49 + channel.writeAndFlush("[" + incoming.remoteAddress() + "]" + s + "\n");
  50 + } else {
  51 + channel.writeAndFlush("[you]" + s + "\n");
  52 + }
  53 + }
  54 + }
  55 +
  56 + @Override
  57 + public void channelActive(ChannelHandlerContext ctx) throws Exception { // (5)
  58 + Channel incoming = ctx.channel();
  59 + System.out.println("SimpleChatClient:"+incoming.remoteAddress()+"在线");
  60 + }
  61 +
  62 + @Override
  63 + public void channelInactive(ChannelHandlerContext ctx) throws Exception { // (6)
  64 + Channel incoming = ctx.channel();
  65 + System.out.println("SimpleChatClient:"+incoming.remoteAddress()+"掉线");
  66 + }
  67 + @Override
  68 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  69 + Channel incoming = ctx.channel();
  70 + System.out.println("SimpleChatClient:"+incoming.remoteAddress()+"异常");
  71 + // 当出现异常就关闭连接
  72 + cause.printStackTrace();
  73 + ctx.close();
  74 + }
  75 +}
  1 +package com.waylau.netty.demo.simplechat;
  2 +
  3 +
  4 +import io.netty.channel.ChannelInitializer;
  5 +import io.netty.channel.ChannelPipeline;
  6 +import io.netty.channel.socket.SocketChannel;
  7 +import io.netty.handler.codec.DelimiterBasedFrameDecoder;
  8 +import io.netty.handler.codec.Delimiters;
  9 +import io.netty.handler.codec.string.StringDecoder;
  10 +import io.netty.handler.codec.string.StringEncoder;
  11 +
  12 +/**
  13 + * 服务端 ChannelInitializer
  14 + *
  15 + * @author waylau.com
  16 + * @date 2015-2-26
  17 + */
  18 +public class SimpleChatServerInitializer extends
  19 + ChannelInitializer<SocketChannel> {
  20 +
  21 + @Override
  22 + public void initChannel(SocketChannel ch) throws Exception {
  23 + ChannelPipeline pipeline = ch.pipeline();
  24 +
  25 + pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
  26 + pipeline.addLast("decoder", new StringDecoder());
  27 + pipeline.addLast("encoder", new StringEncoder());
  28 + pipeline.addLast("handler", new SimpleChatServerHandler());
  29 +
  30 + System.out.println("SimpleChatClient:"+ch.remoteAddress() +"连接上");
  31 + }
  32 +}
  1 +package com.waylau.netty.demo.telnet;
  2 +
  3 +import io.netty.bootstrap.Bootstrap;
  4 +import io.netty.channel.Channel;
  5 +import io.netty.channel.ChannelFuture;
  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.ssl.SslContext;
  10 +import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
  11 +
  12 +import java.io.BufferedReader;
  13 +import java.io.InputStreamReader;
  14 +
  15 +/**
  16 + * Simplistic telnet client.
  17 + */
  18 +public final class TelnetClient {
  19 +
  20 + static final boolean SSL = System.getProperty("ssl") != null;
  21 + static final String HOST = System.getProperty("host", "127.0.0.1");
  22 + static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8992" : "8023"));
  23 +
  24 + public static void main(String[] args) throws Exception {
  25 + // Configure SSL.
  26 + final SslContext sslCtx;
  27 + if (SSL) {
  28 + sslCtx = SslContext.newClientContext(InsecureTrustManagerFactory.INSTANCE);
  29 + } else {
  30 + sslCtx = null;
  31 + }
  32 +
  33 + EventLoopGroup group = new NioEventLoopGroup();
  34 + try {
  35 + Bootstrap b = new Bootstrap();
  36 + b.group(group)
  37 + .channel(NioSocketChannel.class)
  38 + .handler(new TelnetClientInitializer(sslCtx));
  39 +
  40 + // Start the connection attempt.
  41 + Channel ch = b.connect(HOST, PORT).sync().channel();
  42 +
  43 + // Read commands from the stdin.
  44 + ChannelFuture lastWriteFuture = null;
  45 + BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
  46 + for (;;) {
  47 + String line = in.readLine();
  48 + if (line == null) {
  49 + break;
  50 + }
  51 +
  52 + // Sends the received line to the server.
  53 + lastWriteFuture = ch.writeAndFlush(line + "\r\n");
  54 +
  55 + // If user typed the 'bye' command, wait until the server closes
  56 + // the connection.
  57 + if ("bye".equals(line.toLowerCase())) {
  58 + ch.closeFuture().sync();
  59 + break;
  60 + }
  61 + }
  62 +
  63 + // Wait until all messages are flushed before closing the channel.
  64 + if (lastWriteFuture != null) {
  65 + lastWriteFuture.sync();
  66 + }
  67 + } finally {
  68 + group.shutdownGracefully();
  69 + }
  70 + }
  71 +}
  1 +package com.waylau.netty.demo.telnet;
  2 +
  3 +import io.netty.channel.ChannelHandler.Sharable;
  4 +import io.netty.channel.ChannelHandlerContext;
  5 +import io.netty.channel.SimpleChannelInboundHandler;
  6 +
  7 +/**
  8 + * Handles a client-side channel.
  9 + */
  10 +@Sharable
  11 +public class TelnetClientHandler extends SimpleChannelInboundHandler<String> {
  12 +
  13 + protected void messageReceived(ChannelHandlerContext ctx, String msg) {
  14 + System.err.println(msg);
  15 + }
  16 +
  17 + @Override
  18 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  19 + cause.printStackTrace();
  20 + ctx.close();
  21 + }
  22 +
  23 + @Override
  24 + protected void channelRead0(ChannelHandlerContext ctx, String msg)
  25 + throws Exception {
  26 + // TODO Auto-generated method stub
  27 +
  28 + }
  29 +}
  1 +package com.waylau.netty.demo.telnet;
  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 +import io.netty.handler.ssl.SslContext;
  11 +
  12 +/**
  13 + * Creates a newly configured {@link ChannelPipeline} for a new channel.
  14 + */
  15 +public class TelnetClientInitializer extends ChannelInitializer<SocketChannel> {
  16 +
  17 + private static final StringDecoder DECODER = new StringDecoder();
  18 + private static final StringEncoder ENCODER = new StringEncoder();
  19 +
  20 + private static final TelnetClientHandler CLIENT_HANDLER = new TelnetClientHandler();
  21 +
  22 + private final SslContext sslCtx;
  23 +
  24 + public TelnetClientInitializer(SslContext sslCtx) {
  25 + this.sslCtx = sslCtx;
  26 + }
  27 +
  28 + @Override
  29 + public void initChannel(SocketChannel ch) {
  30 + ChannelPipeline pipeline = ch.pipeline();
  31 +
  32 + if (sslCtx != null) {
  33 + pipeline.addLast(sslCtx.newHandler(ch.alloc(), TelnetClient.HOST, TelnetClient.PORT));
  34 + }
  35 +
  36 + // Add the text line codec combination first,
  37 + pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
  38 + pipeline.addLast(DECODER);
  39 + pipeline.addLast(ENCODER);
  40 +
  41 + // and then business logic.
  42 + pipeline.addLast(CLIENT_HANDLER);
  43 + }
  44 +}
  1 +package com.waylau.netty.demo.telnet;
  2 +
  3 +import io.netty.bootstrap.ServerBootstrap;
  4 +import io.netty.channel.EventLoopGroup;
  5 +import io.netty.channel.nio.NioEventLoopGroup;
  6 +import io.netty.channel.socket.nio.NioServerSocketChannel;
  7 +import io.netty.handler.logging.LogLevel;
  8 +import io.netty.handler.logging.LoggingHandler;
  9 +import io.netty.handler.ssl.SslContext;
  10 +import io.netty.handler.ssl.util.SelfSignedCertificate;
  11 +
  12 +/**
  13 + * Simplistic telnet server.
  14 + */
  15 +public final class TelnetServer {
  16 +
  17 + static final boolean SSL = System.getProperty("ssl") != null;
  18 + static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8992" : "8023"));
  19 +
  20 + public static void main(String[] args) throws Exception {
  21 + // Configure SSL.
  22 + final SslContext sslCtx;
  23 + if (SSL) {
  24 + SelfSignedCertificate ssc = new SelfSignedCertificate();
  25 + sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
  26 + } else {
  27 + sslCtx = null;
  28 + }
  29 +
  30 + EventLoopGroup bossGroup = new NioEventLoopGroup(1);
  31 + EventLoopGroup workerGroup = new NioEventLoopGroup();
  32 + try {
  33 + ServerBootstrap b = new ServerBootstrap();
  34 + b.group(bossGroup, workerGroup)
  35 + .channel(NioServerSocketChannel.class)
  36 + .handler(new LoggingHandler(LogLevel.INFO))
  37 + .childHandler(new TelnetServerInitializer(sslCtx));
  38 +
  39 + b.bind(PORT).sync().channel().closeFuture().sync();
  40 + } finally {
  41 + bossGroup.shutdownGracefully();
  42 + workerGroup.shutdownGracefully();
  43 + }
  44 + }
  45 +}
  1 +package com.waylau.netty.demo.telnet;
  2 +
  3 +import io.netty.channel.ChannelFuture;
  4 +import io.netty.channel.ChannelFutureListener;
  5 +import io.netty.channel.ChannelHandler.Sharable;
  6 +import io.netty.channel.ChannelHandlerContext;
  7 +import io.netty.channel.SimpleChannelInboundHandler;
  8 +
  9 +import java.net.InetAddress;
  10 +import java.util.Date;
  11 +
  12 +/**
  13 + * Handles a server-side channel.
  14 + */
  15 +@Sharable
  16 +public class TelnetServerHandler extends SimpleChannelInboundHandler<String> {
  17 +
  18 + @Override
  19 + public void channelActive(ChannelHandlerContext ctx) throws Exception {
  20 + // Send greeting for a new connection.
  21 + ctx.write("Welcome to " + InetAddress.getLocalHost().getHostName() + "!\r\n");
  22 + ctx.write("It is " + new Date() + " now.\r\n");
  23 + ctx.flush();
  24 + }
  25 +
  26 + public void messageReceived(ChannelHandlerContext ctx, String request) {
  27 + // Generate and write a response.
  28 + String response;
  29 + boolean close = false;
  30 + if (request.isEmpty()) {
  31 + response = "Please type something.\r\n";
  32 + } else if ("bye".equals(request.toLowerCase())) {
  33 + response = "Have a good day!\r\n";
  34 + close = true;
  35 + } else {
  36 + response = "Did you say '" + request + "'?\r\n";
  37 + }
  38 +
  39 + // We do not need to write a ChannelBuffer here.
  40 + // We know the encoder inserted at TelnetPipelineFactory will do the conversion.
  41 + ChannelFuture future = ctx.write(response);
  42 +
  43 + // Close the connection after sending 'Have a good day!'
  44 + // if the client has sent 'bye'.
  45 + if (close) {
  46 + future.addListener(ChannelFutureListener.CLOSE);
  47 + }
  48 + }
  49 +
  50 + @Override
  51 + public void channelReadComplete(ChannelHandlerContext ctx) {
  52 + ctx.flush();
  53 + }
  54 +
  55 + @Override
  56 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  57 + cause.printStackTrace();
  58 + ctx.close();
  59 + }
  60 +
  61 + @Override
  62 + protected void channelRead0(ChannelHandlerContext ctx, String msg)
  63 + throws Exception {
  64 + // TODO Auto-generated method stub
  65 +
  66 + }
  67 +}
  1 +package com.waylau.netty.demo.telnet;
  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 +import io.netty.handler.ssl.SslContext;
  11 +
  12 +/**
  13 + * Creates a newly configured {@link ChannelPipeline} for a new channel.
  14 + */
  15 +public class TelnetServerInitializer extends ChannelInitializer<SocketChannel> {
  16 +
  17 + private static final StringDecoder DECODER = new StringDecoder();
  18 + private static final StringEncoder ENCODER = new StringEncoder();
  19 +
  20 + private static final TelnetServerHandler SERVER_HANDLER = new TelnetServerHandler();
  21 +
  22 + private final SslContext sslCtx;
  23 +
  24 + public TelnetServerInitializer(SslContext sslCtx) {
  25 + this.sslCtx = sslCtx;
  26 + }
  27 +
  28 + @Override
  29 + public void initChannel(SocketChannel ch) throws Exception {
  30 + ChannelPipeline pipeline = ch.pipeline();
  31 +
  32 + if (sslCtx != null) {
  33 + pipeline.addLast(sslCtx.newHandler(ch.alloc()));
  34 + }
  35 +
  36 + // Add the text line codec combination first,
  37 + pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
  38 + // the encoder and decoder are static as these are sharable
  39 + pipeline.addLast(DECODER);
  40 + pipeline.addLast(ENCODER);
  41 +
  42 + // and then business logic.
  43 + pipeline.addLast(SERVER_HANDLER);
  44 + }
  45 +}
  1 +package com.waylau.netty.demo.time;
  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 +
  12 +public class TimeClient {
  13 +
  14 + public static void main(String[] args) throws Exception {
  15 +
  16 + String host = "127.0.0.1";// args[0];
  17 + int port = 8080;//Integer.parseInt(args[1]);
  18 + EventLoopGroup workerGroup = new NioEventLoopGroup();
  19 +
  20 + try {
  21 + Bootstrap b = new Bootstrap(); // (1)
  22 + b.group(workerGroup); // (2)
  23 + b.channel(NioSocketChannel.class); // (3)
  24 + b.option(ChannelOption.SO_KEEPALIVE, true); // (4)
  25 + b.handler(new ChannelInitializer<SocketChannel>() {
  26 + @Override
  27 + public void initChannel(SocketChannel ch) throws Exception {
  28 + ch.pipeline().addLast(new TimeClientHandler());
  29 + }
  30 + });
  31 +
  32 + // 启动客户端
  33 + ChannelFuture f = b.connect(host, port).sync(); // (5)
  34 +
  35 + // 等待连接关闭
  36 + f.channel().closeFuture().sync();
  37 + } finally {
  38 + workerGroup.shutdownGracefully();
  39 + }
  40 + }
  41 +}
  1 +package com.waylau.netty.demo.time;
  2 +
  3 +import java.util.Date;
  4 +
  5 +import io.netty.buffer.ByteBuf;
  6 +import io.netty.channel.ChannelHandlerContext;
  7 +import io.netty.channel.ChannelInboundHandlerAdapter;
  8 +
  9 +public class TimeClientHandler extends ChannelInboundHandlerAdapter {
  10 +
  11 + @Override
  12 + public void channelRead(ChannelHandlerContext ctx, Object msg) {
  13 + ByteBuf m = (ByteBuf) msg; // (1)
  14 + try {
  15 + long currentTimeMillis = (m.readUnsignedInt() - 2208988800L) * 1000L;
  16 + System.out.println(new Date(currentTimeMillis));
  17 + ctx.close();
  18 + } finally {
  19 + m.release();
  20 + }
  21 + }
  22 +
  23 + @Override
  24 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  25 + cause.printStackTrace();
  26 + ctx.close();
  27 + }
  28 +}
  1 +package com.waylau.netty.demo.time;
  2 +
  3 +import io.netty.bootstrap.ServerBootstrap;
  4 +
  5 +import io.netty.channel.ChannelFuture;
  6 +import io.netty.channel.ChannelInitializer;
  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.SocketChannel;
  11 +import io.netty.channel.socket.nio.NioServerSocketChannel;
  12 +
  13 +/**
  14 + * 时间服务器
  15 + */
  16 +public class TimeServer {
  17 +
  18 + private int port;
  19 +
  20 + public TimeServer(int port) {
  21 + this.port = port;
  22 + }
  23 +
  24 + public void run() throws Exception {
  25 + EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
  26 + EventLoopGroup workerGroup = new NioEventLoopGroup();
  27 + try {
  28 + ServerBootstrap b = new ServerBootstrap(); // (2)
  29 + b.group(bossGroup, workerGroup)
  30 + .channel(NioServerSocketChannel.class) // (3)
  31 + .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
  32 + @Override
  33 + public void initChannel(SocketChannel ch) throws Exception {
  34 + ch.pipeline().addLast(new TimeServerHandler());
  35 + }
  36 + })
  37 + .option(ChannelOption.SO_BACKLOG, 128) // (5)
  38 + .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
  39 +
  40 + // 绑定端口,开始接收进来的连接
  41 + ChannelFuture f = b.bind(port).sync(); // (7)
  42 +
  43 + // 等待服务器 socket 关闭 。
  44 + // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。
  45 + f.channel().closeFuture().sync();
  46 + } finally {
  47 + workerGroup.shutdownGracefully();
  48 + bossGroup.shutdownGracefully();
  49 + }
  50 + }
  51 +
  52 + public static void main(String[] args) throws Exception {
  53 + int port;
  54 + if (args.length > 0) {
  55 + port = Integer.parseInt(args[0]);
  56 + } else {
  57 + port = 8080;
  58 + }
  59 + new TimeServer(port).run();
  60 + }
  61 +}
  1 +package com.waylau.netty.demo.time;
  2 +
  3 +import io.netty.buffer.ByteBuf;
  4 +import io.netty.channel.ChannelFuture;
  5 +import io.netty.channel.ChannelFutureListener;
  6 +import io.netty.channel.ChannelHandlerContext;
  7 +import io.netty.channel.ChannelInboundHandlerAdapter;
  8 +
  9 +public class TimeServerHandler extends ChannelInboundHandlerAdapter {
  10 +
  11 + @Override
  12 + public void channelActive(final ChannelHandlerContext ctx) { // (1)
  13 + final ByteBuf time = ctx.alloc().buffer(4); // (2)
  14 + time.writeInt((int) (System.currentTimeMillis() / 1000L + 2208988800L));
  15 +
  16 + final ChannelFuture f = ctx.writeAndFlush(time); // (3)
  17 + f.addListener(new ChannelFutureListener() {
  18 + @Override
  19 + public void operationComplete(ChannelFuture future) {
  20 + assert f == future;
  21 + ctx.close();
  22 + }
  23 + }); // (4)
  24 + }
  25 +
  26 + @Override
  27 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  28 + cause.printStackTrace();
  29 + ctx.close();
  30 + }
  31 +}
  1 +package com.waylau.netty.demo.websocketchat;
  2 +
  3 +import io.netty.channel.Channel;
  4 +import io.netty.channel.ChannelFuture;
  5 +import io.netty.channel.ChannelFutureListener;
  6 +import io.netty.channel.ChannelHandlerContext;
  7 +import io.netty.channel.DefaultFileRegion;
  8 +import io.netty.channel.SimpleChannelInboundHandler;
  9 +import io.netty.handler.codec.http.DefaultFullHttpResponse;
  10 +import io.netty.handler.codec.http.DefaultHttpResponse;
  11 +import io.netty.handler.codec.http.FullHttpRequest;
  12 +import io.netty.handler.codec.http.FullHttpResponse;
  13 +import io.netty.handler.codec.http.HttpHeaders;
  14 +import io.netty.handler.codec.http.HttpResponse;
  15 +import io.netty.handler.codec.http.HttpResponseStatus;
  16 +import io.netty.handler.codec.http.HttpVersion;
  17 +import io.netty.handler.codec.http.LastHttpContent;
  18 +import io.netty.handler.ssl.SslHandler;
  19 +import io.netty.handler.stream.ChunkedNioFile;
  20 +
  21 +import java.io.File;
  22 +import java.io.RandomAccessFile;
  23 +import java.net.URISyntaxException;
  24 +import java.net.URL;
  25 +
  26 +/**
  27 + * 处理 Http 请求
  28 + * @author waylau.com
  29 + * @date 2015-3-26
  30 + */
  31 +public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> { //1
  32 + private final String wsUri;
  33 + private static final File INDEX;
  34 +
  35 + static {
  36 + URL location = HttpRequestHandler.class.getProtectionDomain().getCodeSource().getLocation();
  37 + try {
  38 + String path = location.toURI() + "WebsocketChatClient.html";
  39 + path = !path.contains("file:") ? path : path.substring(5);
  40 + INDEX = new File(path);
  41 + } catch (URISyntaxException e) {
  42 + throw new IllegalStateException("Unable to locate WebsocketChatClient.html", e);
  43 + }
  44 + }
  45 +
  46 + public HttpRequestHandler(String wsUri) {
  47 + this.wsUri = wsUri;
  48 + }
  49 +
  50 + @Override
  51 + public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
  52 + if (wsUri.equalsIgnoreCase(request.getUri())) {
  53 + ctx.fireChannelRead(request.retain()); //2
  54 + } else {
  55 + if (HttpHeaders.is100ContinueExpected(request)) {
  56 + send100Continue(ctx); //3
  57 + }
  58 +
  59 + RandomAccessFile file = new RandomAccessFile(INDEX, "r");//4
  60 +
  61 + HttpResponse response = new DefaultHttpResponse(request.getProtocolVersion(), HttpResponseStatus.OK);
  62 + response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/html; charset=UTF-8");
  63 +
  64 + boolean keepAlive = HttpHeaders.isKeepAlive(request);
  65 +
  66 + if (keepAlive) { //5
  67 + response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, file.length());
  68 + response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
  69 + }
  70 + ctx.write(response); //6
  71 +
  72 + if (ctx.pipeline().get(SslHandler.class) == null) { //7
  73 + ctx.write(new DefaultFileRegion(file.getChannel(), 0, file.length()));
  74 + } else {
  75 + ctx.write(new ChunkedNioFile(file.getChannel()));
  76 + }
  77 + ChannelFuture future = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); //8
  78 + if (!keepAlive) {
  79 + future.addListener(ChannelFutureListener.CLOSE); //9
  80 + }
  81 +
  82 + file.close();
  83 + }
  84 + }
  85 +
  86 + private static void send100Continue(ChannelHandlerContext ctx) {
  87 + FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);
  88 + ctx.writeAndFlush(response);
  89 + }
  90 +
  91 + @Override
  92 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
  93 + throws Exception {
  94 + Channel incoming = ctx.channel();
  95 + System.out.println("Client:"+incoming.remoteAddress()+"异常");
  96 + // 当出现异常就关闭连接
  97 + cause.printStackTrace();
  98 + ctx.close();
  99 + }
  100 +}
  1 +package com.waylau.netty.demo.websocketchat;
  2 +
  3 +
  4 +import io.netty.channel.Channel;
  5 +import io.netty.channel.ChannelHandlerContext;
  6 +import io.netty.channel.SimpleChannelInboundHandler;
  7 +import io.netty.channel.group.ChannelGroup;
  8 +import io.netty.channel.group.DefaultChannelGroup;
  9 +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
  10 +import io.netty.util.concurrent.GlobalEventExecutor;
  11 +
  12 +/**
  13 + * 处理TextWebSocketFrame
  14 + *
  15 + * @author waylau.com
  16 + * 2015年3月26日
  17 + */
  18 +public class TextWebSocketFrameHandler extends
  19 + SimpleChannelInboundHandler<TextWebSocketFrame> {
  20 +
  21 + public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
  22 +
  23 + @Override
  24 + protected void channelRead0(ChannelHandlerContext ctx,
  25 + TextWebSocketFrame msg) throws Exception { // (1)
  26 + Channel incoming = ctx.channel();
  27 + for (Channel channel : channels) {
  28 + if (channel != incoming){
  29 + channel.writeAndFlush(new TextWebSocketFrame("[" + incoming.remoteAddress() + "]" + msg.text()));
  30 + } else {
  31 + channel.writeAndFlush(new TextWebSocketFrame("[you]" + msg.text() ));
  32 + }
  33 + }
  34 + }
  35 +
  36 + @Override
  37 + public void handlerAdded(ChannelHandlerContext ctx) throws Exception { // (2)
  38 + Channel incoming = ctx.channel();
  39 +
  40 + // Broadcast a message to multiple Channels
  41 + channels.writeAndFlush(new TextWebSocketFrame("[SERVER] - " + incoming.remoteAddress() + " 加入"));
  42 +
  43 + channels.add(incoming);
  44 + System.out.println("Client:"+incoming.remoteAddress() +"加入");
  45 + }
  46 +
  47 + @Override
  48 + public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { // (3)
  49 + Channel incoming = ctx.channel();
  50 +
  51 + // Broadcast a message to multiple Channels
  52 + channels.writeAndFlush(new TextWebSocketFrame("[SERVER] - " + incoming.remoteAddress() + " 离开"));
  53 +
  54 + System.out.println("Client:"+incoming.remoteAddress() +"离开");
  55 +
  56 + // A closed Channel is automatically removed from ChannelGroup,
  57 + // so there is no need to do "channels.remove(ctx.channel());"
  58 + }
  59 +
  60 + @Override
  61 + public void channelActive(ChannelHandlerContext ctx) throws Exception { // (5)
  62 + Channel incoming = ctx.channel();
  63 + System.out.println("Client:"+incoming.remoteAddress()+"在线");
  64 + }
  65 +
  66 + @Override
  67 + public void channelInactive(ChannelHandlerContext ctx) throws Exception { // (6)
  68 + Channel incoming = ctx.channel();
  69 + System.out.println("Client:"+incoming.remoteAddress()+"掉线");
  70 + }
  71 +
  72 + @Override
  73 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) // (7)
  74 + throws Exception {
  75 + Channel incoming = ctx.channel();
  76 + System.out.println("Client:"+incoming.remoteAddress()+"异常");
  77 + // 当出现异常就关闭连接
  78 + cause.printStackTrace();
  79 + ctx.close();
  80 + }
  81 +
  82 +}
  1 +package com.waylau.netty.demo.websocketchat;
  2 +
  3 +import io.netty.bootstrap.ServerBootstrap;
  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.NioServerSocketChannel;
  9 +
  10 +/**
  11 + * Websocket 聊天服务器-服务端
  12 + *
  13 + * @author waylau.com
  14 + * @date 2015-3-7
  15 + */
  16 +public class WebsocketChatServer {
  17 +
  18 + private int port;
  19 +
  20 + public WebsocketChatServer(int port) {
  21 + this.port = port;
  22 + }
  23 +
  24 + public void run() throws Exception {
  25 +
  26 + EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
  27 + EventLoopGroup workerGroup = new NioEventLoopGroup();
  28 + try {
  29 + ServerBootstrap b = new ServerBootstrap(); // (2)
  30 + b.group(bossGroup, workerGroup)
  31 + .channel(NioServerSocketChannel.class) // (3)
  32 + .childHandler(new WebsocketChatServerInitializer()) //(4)
  33 + .option(ChannelOption.SO_BACKLOG, 128) // (5)
  34 + .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)
  35 +
  36 + System.out.println("WebsocketChatServer 启动了" + port);
  37 +
  38 + // 绑定端口,开始接收进来的连接
  39 + ChannelFuture f = b.bind(port).sync(); // (7)
  40 +
  41 + // 等待服务器 socket 关闭 。
  42 + // 在这个例子中,这不会发生,但你可以优雅地关闭你的服务器。
  43 + f.channel().closeFuture().sync();
  44 +
  45 + } finally {
  46 + workerGroup.shutdownGracefully();
  47 + bossGroup.shutdownGracefully();
  48 +
  49 + System.out.println("WebsocketChatServer 关闭了");
  50 + }
  51 + }
  52 +
  53 + public static void main(String[] args) throws Exception {
  54 + int port;
  55 + if (args.length > 0) {
  56 + port = Integer.parseInt(args[0]);
  57 + } else {
  58 + port = 8080;
  59 + }
  60 + new WebsocketChatServer(port).run();
  61 +
  62 + }
  63 +}
  1 +package com.waylau.netty.demo.websocketchat;
  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.codec.http.websocketx.WebSocketServerProtocolHandler;
  9 +import io.netty.handler.stream.ChunkedWriteHandler;
  10 +
  11 +/**
  12 + * 服务端 ChannelInitializer
  13 + *
  14 + * @author waylau.com
  15 + * @date 2015-3-13
  16 + */
  17 +public class WebsocketChatServerInitializer extends
  18 + ChannelInitializer<SocketChannel> { //1
  19 +
  20 + @Override
  21 + public void initChannel(SocketChannel ch) throws Exception {//2
  22 + ChannelPipeline pipeline = ch.pipeline();
  23 +
  24 + pipeline.addLast(new HttpServerCodec());
  25 + pipeline.addLast(new HttpObjectAggregator(64*1024));
  26 + pipeline.addLast(new ChunkedWriteHandler());
  27 + pipeline.addLast(new HttpRequestHandler("/ws"));
  28 + pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
  29 + pipeline.addLast(new TextWebSocketFrameHandler());
  30 +
  31 + }
  32 +}
  1 +/**
  2 + *
  3 + */
  4 +package com.waylau.netty.util;
  5 +
  6 +import java.io.ByteArrayInputStream;
  7 +import java.io.ByteArrayOutputStream;
  8 +import java.io.IOException;
  9 +import java.io.ObjectInputStream;
  10 +import java.io.ObjectOutputStream;
  11 +
  12 +/**
  13 + * 说明:
  14 + *
  15 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月9日
  16 + */
  17 +public class ByteObjConverter {
  18 +
  19 + public static Object ByteToObject(byte[] bytes) {
  20 + Object obj = null;
  21 + ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
  22 + ObjectInputStream oi = null;
  23 + try {
  24 + oi = new ObjectInputStream(bi);
  25 + obj = oi.readObject();
  26 + } catch (Exception e) {
  27 + e.printStackTrace();
  28 + } finally {
  29 + try {
  30 + bi.close();
  31 + } catch (IOException e) {
  32 + e.printStackTrace();
  33 + }
  34 + try {
  35 + oi.close();
  36 + } catch (IOException e) {
  37 + e.printStackTrace();
  38 + }
  39 + }
  40 + return obj;
  41 + }
  42 +
  43 + public static byte[] ObjectToByte(Object obj) {
  44 + byte[] bytes = null;
  45 + ByteArrayOutputStream bo = new ByteArrayOutputStream();
  46 + ObjectOutputStream oo = null;
  47 + try {
  48 + oo = new ObjectOutputStream(bo);
  49 + oo.writeObject(obj);
  50 + bytes = bo.toByteArray();
  51 + } catch (Exception e) {
  52 + e.printStackTrace();
  53 + } finally {
  54 + try {
  55 + bo.close();
  56 + } catch (IOException e) {
  57 + e.printStackTrace();
  58 + }
  59 + try {
  60 + oo.close();
  61 + } catch (IOException e) {
  62 + e.printStackTrace();
  63 + }
  64 + }
  65 + return (bytes);
  66 + }
  67 +}
  1 +/**
  2 + *
  3 + */
  4 +/**
  5 + * 说明:工具包
  6 + *
  7 + * @author <a href="http://www.waylau.com">waylau.com</a> 2015年11月10日
  8 + */
  9 +package com.waylau.netty.util;
  1 +<!DOCTYPE html>
  2 +<html>
  3 +<head>
  4 +<meta charset="UTF-8">
  5 +<title>WebSocket Chat</title>
  6 +</head>
  7 +<body>
  8 + <script type="text/javascript">
  9 + var socket;
  10 + if (!window.WebSocket) {
  11 + window.WebSocket = window.MozWebSocket;
  12 + }
  13 + if (window.WebSocket) {
  14 + socket = new WebSocket("ws://localhost:8080/ws");
  15 + socket.onmessage = function(event) {
  16 + var ta = document.getElementById('responseText');
  17 + ta.value = ta.value + '\n' + event.data
  18 + };
  19 + socket.onopen = function(event) {
  20 + var ta = document.getElementById('responseText');
  21 + ta.value = "连接开启!";
  22 + };
  23 + socket.onclose = function(event) {
  24 + var ta = document.getElementById('responseText');
  25 + ta.value = ta.value + "连接被关闭";
  26 + };
  27 + } else {
  28 + alert("你的浏览器不支持 WebSocket!");
  29 + }
  30 +
  31 + function send(message) {
  32 + if (!window.WebSocket) {
  33 + return;
  34 + }
  35 + if (socket.readyState == WebSocket.OPEN) {
  36 + socket.send(message);
  37 + } else {
  38 + alert("连接没有开启.");
  39 + }
  40 + }
  41 + </script>
  42 + <form onsubmit="return false;">
  43 + <h3>WebSocket 聊天室:</h3>
  44 + <textarea id="responseText" style="width: 500px; height: 300px;"></textarea>
  45 + <br>
  46 + <input type="text" name="message" style="width: 300px" value="Welcome to www.waylau.com">
  47 + <input type="button" value="发送消息" onclick="send(this.form.message.value)">
  48 + <input type="button" onclick="javascript:document.getElementById('responseText').value=''" value="清空聊天记录">
  49 + </form>
  50 + <br>
  51 + <br>
  52 + <a href="https://waylau.com/" >更多例子请访问 waylau.com</a>
  53 +</body>
  54 +</html>
  1 +package com.waylau.netty;
  2 +
  3 +import junit.framework.Test;
  4 +import junit.framework.TestCase;
  5 +import junit.framework.TestSuite;
  6 +
  7 +/**
  8 + * Unit test for simple App.
  9 + */
  10 +public class AppTest
  11 + extends TestCase
  12 +{
  13 + /**
  14 + * Create the test case
  15 + *
  16 + * @param testName name of the test case
  17 + */
  18 + public AppTest( String testName )
  19 + {
  20 + super( testName );
  21 + }
  22 +
  23 + /**
  24 + * @return the suite of tests being tested
  25 + */
  26 + public static Test suite()
  27 + {
  28 + return new TestSuite( AppTest.class );
  29 + }
  30 +
  31 + /**
  32 + * Rigourous Test :-)
  33 + */
  34 + public void testApp()
  35 + {
  36 + assertTrue( true );
  37 + }
  38 +}