項目需要,要寫一個服務器作爲數據中轉站,服務器接收客戶端發送的數據,再轉發給其他客戶端。
客戶端可以自己寫一個測試是否可以連接和接收數據,也可以是4G模塊或者單片機啥的。
客戶端代碼:
我的項目目錄結構:
代碼如下:
NettyServer.java
import io.netty.bootstrap.ServerBootstrap;
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.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
public class NettyServer {
public static void startServer(String hostName, int port){
startServer0(hostName,port);
}
private static void startServer0(String hostname, int port) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new NettyServerHandler());
}
});
ChannelFuture channelFuture = serverBootstrap.bind(hostname, port).sync();
System.out.println("服務提供者已經啓動");
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
NettyServerHandler.java
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
public class NettyServerHandler extends SimpleChannelInboundHandler<String> {
private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
/**
* 服務器端收到任何一個客戶端的消息都會觸發這個方法
* 連接的客戶端向服務器端發送消息,那麼其他客戶端都收到此消息,自己收到【自己】+消息
*/
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String msg) throws Exception {
Channel channel = channelHandlerContext.channel();
channelGroup.forEach(ch -> {
if(channel != ch){
ch.writeAndFlush(channel.remoteAddress() +" 發送的消息:" +msg+" \n");
}else {
ch.writeAndFlush(" 【自己】"+msg +" \n");
}
});
}
//表示服務端與客戶端連接建立
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
/**
* 調用channelGroup的writeAndFlush其實就相當於channelGroup中的每個channel都writeAndFlush
*
* 先去廣播,再將自己加入到channelGroup中
*/
channelGroup.writeAndFlush(" 【客戶端】 -" +channel.remoteAddress() +" 加入\n");
channelGroup.add(channel);
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
channelGroup.writeAndFlush(" 【客戶端】 -" +channel.remoteAddress() +" 離開\n");
//驗證一下每次客戶端斷開連接,連接自動地從channelGroup中刪除調。
System.out.println(channelGroup.size());
//當客戶端和服務端斷開連接的時候,下面的那段代碼netty會自動調用,所以不需要人爲的去調用它
//channelGroup.remove(channel);
}
//連接處於活動狀態
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
System.out.println(channel.remoteAddress() +" 上線了");
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
System.out.println(channel.remoteAddress() +" 下線了");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
啓動類:ServerMain.java
public class ServerMain {
public static void main(String[] args) {
NettyServer.startServer("ip",port);
}
}
客戶端代碼:
NettyClient.java
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
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;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class NettyClient {
public static void startClient(String hostName, int port) throws Exception {
initClient(hostName, port);
}
private static void initClient(String hostName, int port) throws Exception{
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new NettyClientHandler());
}
});
Channel channel = bootstrap.connect(hostName, port).sync().channel();
//標準輸入
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
//利用死循環,不斷讀取客戶端在控制檯上的輸入內容
for (;;){
channel.writeAndFlush(bufferedReader.readLine() +"\r\n");
}
}catch (Exception e){
e.printStackTrace();
}finally {
eventLoopGroup.shutdownGracefully();
}
}
}
NettyClientHandler.java
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class NettyClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
System.out.println("...."+s);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
啓動類:ClientMain.java
public class ClientMain {
public static void main(String[] args) throws Exception {
NettyClient.startClient("ip",port);
}
}
附:打包流程
https://blog.csdn.net/weixin_42089175/article/details/89113271
我是按照這篇教程操作的
附:上傳jar包到雲服務器
scp 本地jar包路徑 root@雲服務器ip:想要上傳到的雲服務器的路徑
附:在雲服務器持續在後臺運行jar包
nohup java -jar jar包名稱 >/dev/null 2>&1 &
附:查看該端口接收和轉發的數據
telnet ip port