在controller中给netty服务器发送消息
1.客户端:客户端的配置,业务处理逻辑,从控制器中给Netty服务器发送消息
2.服务端:服务端的配置和业务处理逻辑
io.netty
netty-all
5.0.0.Alpha1
注:其他依赖根据需要添加
客户端配置类(读取application.yml中的配置)
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class NettyConfig {
/**
* 主机
*/
@Value("${netty.host}")
private String host;
/**
* 端口号
*/
@Value("${netty.port}")
private int port;
@Bean
public NettyClient nettyClient() {
return new NettyClient(host,port);
}
}
application.yml
server:
port: 8900
netty:
port : 8899
host: 127.0.0.1
客户端配置代码(完成连接netty服务器的功能)
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
@Component
public class NettyClient {
//主机
private String host;
//端口号
private int port;
private EventLoopGroup group;
private Bootstrap b;
private ChannelFuture cf;
public NettyClient(String host, int port) {
this.host = host;
this.port = port;
}
@PostConstruct //此注解会在类创建时被调用
public void init() throws InterruptedException {
group = new NioEventLoopGroup();
b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
ChannelPipeline pipeline = sc.pipeline();
}
});
ChannelFuture cf = b.connect(host, port).sync();
}
public void connect() {
try {
this.cf = this.b.connect(host, port).sync(); // 发送json字符串
System.out.println("远程服务器已经连接, 可以进行数据交换..");
} catch (Exception e) {
e.printStackTrace();
}
}
public ChannelFuture getChannelFuture() {
// 如果没有连接先链接
if (this.cf == null) {
this.connect();
} // this.cf.channel().isActive() 这里得到的是链接状态
if (!this.cf.channel().isActive()) {
this.connect();
}
return this.cf;
}
//释放资源
public void close() {
try {
cf.channel().closeFuture().sync();
group.shutdownGracefully();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
客户端业务逻辑处理器
import java.net.InetSocketAddress;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class NettyClientHandler extends SimpleChannelInboundHandler {
@Override
protected void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("收到服务端消息: " + msg);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
String clientIp = insocket.getAddress().getHostAddress();
System.out.println("连接服务器[ip:" + clientIp + ":"+ insocket.getPort()+ "]成功");
ctx.writeAndFlush("active发送的消息");
}
}
客户端Controller代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoop;
@RestController
public class TestController {
@Autowired
NettyClient nettyClient;
@RequestMapping("/test/{msg}")
public String sendMsg(@PathVariable("msg") String msg) {
//获取建立的channel
ChannelFuture cf = nettyClient.getChannelFuture();
Channel channel = cf.channel();
System.out.println("testcontroller获得的channel---" + channel.toString());
byte[] req = msg.getBytes();
ByteBuf sendMsg=Unpooled.buffer(req.length);
sendMsg.writeBytes(req);
cf.channel().writeAndFlush(sendMsg);
return "1";
}
}
服务端配置类(功能:从application.yml中读取配置)
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class NettyConfig {
/**
* 端口号
*/
@Value("${netty.port}")
private int port;
@Bean
public NettyServer nettyServer() {
return new NettyServer(port);
}
}
application.yml
#内嵌tomcat运行端口
server:
port: 8090
#netty服务启动端口
netty:
port : 8899
服务端配置代码(监听客户端请求,建立连接,发送消息等功能)
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
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;
/**
* netty服务端
*
*/
@Component
public class NettyServer {
private Logger log = LoggerFactory.getLogger(getClass());
/**
* 端口号
*/
private int port;
public NettyServer(int port) {
this.port = port;
}
/**
* 启动服务器方法
* @param port
*/
@PostConstruct
public void run() {
EventLoopGroup bossGroup = new NioEventLoopGroup();
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();
}
}
}
服务端处理器
import java.net.InetSocketAddress;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
public class NettyServerHandler extends ChannelHandlerAdapter {
private Logger log = LoggerFactory.getLogger(getClass());
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
byte[] req = new byte[buf.readableBytes()];
buf.readBytes(req);
String body = new String(req, "UTF-8");
System.out.println("服务端收到消息 : " + body);
// StringBuilder sb = null;
// Map result = null;
// try {
// // 报文解析处理
// sb = new StringBuilder();
//// result = JSON.parseObject(msg.toString());
//
// sb.append("服务端返回的数据"+JSON.toJSONString(msg));
// 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 + "]");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// 当出现异常就关闭连接
ctx.close();
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
String clientIp = insocket.getAddress().getHostAddress();
System.out.println("已下线:客户端[ip:" + clientIp + "]");
super.channelInactive(ctx);
}
@Override
public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
super.disconnect(ctx, promise);
}
}
服务端通道初始化代码
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;
public class NettyServerInitializer extends ChannelInitializer {
//初始化channel
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new NettyServerHandler());
}
}
操作
浏览器访问localhost:8900/test/aa
服务端控制台结果
参考
https://blog.csdn.net/column/details/17640.html