Client (main()启动)
NettyClient.java
package com.example.server;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.util.Scanner;
/**
* netty客户端 . <br>
*
* @author hkb
*/
public class NettyClient {
/**
* 主机
*/
private String host;
/**
* 端口号
*/
private int port;
/**
* 客户端昵称
*/
private String name = "client1";
private static String USER_EXIST = "system message: user exist, please change a name";
private static String USER_CONTENT_SPILIT = "#@#";
/**
* 构造函数
*
* @param host
* @param port
*/
public NettyClient(String host, int port) {
this.host = host;
this.port = port;
}
/**
* 连接方法
*/
public void connect() {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.channel(NioSocketChannel.class);
bootstrap.group(group);
bootstrap.option(ChannelOption.TCP_NODELAY, true);
// bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
bootstrap.handler(new NettyClientInitializer());
Channel channel = bootstrap.connect(host, port).sync().channel();
//在主线程中 从键盘读取数据输入到服务器端
Scanner scan = new Scanner(System.in);
while (scan.hasNextLine()) {
String line = scan.nextLine();
System.out.println( line);
// 向服务端server 发送信息
channel.writeAndFlush(line + "\n");
// channel.closeFuture().sync();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}
/**
* 测试入口
*
* @param args
*/
public static void main(String[] args) {
String host = "127.0.0.1";
int port = 11111;
NettyClient nettyClient = new NettyClient(host, port);
nettyClient.connect();
}
}
NettyClientHandler.java
package com.example.server;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* 客户端处理器 . <br>
*
* @author hkb
*/
public class NettyClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("收到服务端消息: " + msg);
}
}
NettyClientInitializer.java
package com.example.server;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
/**
* 客户端初始化 . <br>
*
* @author hkb
*/
public class NettyClientInitializer extends ChannelInitializer<SocketChannel> {
/**
* 初始化channel
*/
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));//inbound
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new NettyClientHandler());
}
}
Server (基于Springboot)
pom.xml
pom文件中添加如下依赖:包括netty及springboot的依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<!-- netty start -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.0.Final</version>
</dependency>
<!-- netty end -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring Boot Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
<version>${spring-boot-starter-redis-version}</version>
</dependency>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
NettyServerListener.java
springboot 的服务监听器
package com.example.config;
import com.example.server.NettyServer;
import org.springframework.beans.factory.annotation.Autowired;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
* netty服务监听器 . <br>
*
* @author hkb
*/
@WebListener
public class NettyServerListener implements ServletContextListener {
/**
* 注入NettyServer
*/
@Autowired
private NettyServer nettyServer;
@Override
public void contextInitialized(ServletContextEvent sce) {
Thread thread = new Thread(new NettyServerThread());
System.out.println("初始化 context");
// 启动netty服务
thread.start();
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
/**
* netty服务启动线程 . <br>
*
* @author hkb
*/
private class NettyServerThread implements Runnable {
@Override
public void run() {
nettyServer.run();
}
}
}
NettyServer.java
package com.example.server;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import static org.junit.internal.Classes.getClass;
/**
* netty服务端 . <br>
*
* @author hkb
*/
@Component
public class NettyServer {
/**
* 日志
*/
private Logger log = LoggerFactory.getLogger(NettyServer.class);
/**
* 端口号
*/
@Value("${netty.port}")
private int port;
/**
* 启动服务器方法
*
* @param
*/
public void run() {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup);
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.option(ChannelOption.SO_BACKLOG, 1024);
serverBootstrap.handler(new LoggingHandler(LogLevel.INFO));
serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true);
serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
serverBootstrap.childHandler(new NettyServerInitializer());
// 绑定端口,开始接收进来的连接
ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
log.info("netty服务启动: [port:" + port + "]");
// 等待服务器socket关闭
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
log.error("netty服务启动异常-" + e.getMessage());
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
NettyServerHandler.java
package com.example.server;
import com.alibaba.fastjson.JSON;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetSocketAddress;
import java.util.Map;
/**
* 服务端处理器 . <br>
*
* @author hkb
*/
public class NettyServerHandler extends SimpleChannelInboundHandler<String> {
/**
* 日志
*/
private Logger log = LoggerFactory.getLogger(getClass());
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
StringBuilder sb = null;
Map<String, Object> result = null;
System.out.println(" 收到客户信息 :" + msg);
try {
// 报文解析处理
sb = new StringBuilder();
result.put("客户信息", msg);
sb.append(result);
sb.append("\n");
ctx.writeAndFlush(sb);
} catch (Exception e) {
String errorCode = "-1\n";
ctx.writeAndFlush(errorCode);
log.error("报文解析失败: " + e.getMessage());
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
String clientIp = insocket.getAddress().getHostAddress();
log.info("收到客户端[ip:" + clientIp + "]连接");
// ctx.fireChannelActive();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// 当出现异常就关闭连接
ctx.close();
}
}
NettyServerInitializer.java
package com.example.server;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
/**
* 服务端初始化 . <br>
*
* @author hkb
*/
public class NettyServerInitializer extends ChannelInitializer<SocketChannel> {
/**
* 初始化channel
*/
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new NettyServerHandler());
}
}
github源码:https://github.com/weiyang00/chat-rooms/tree/master/netty-chat-room