java使用Netty實現點對點聊天
阿新 • • 發佈:2018-12-02
最近學習伺服器開放,實現客戶端(APP)與硬體裝置之間的通訊,我一想到socket,經過查詢資料發現socket實現起來非常麻煩,同時也發現一個比較好的框架netty,覺得很不錯,就開始嘗試用他來擼一個點對點聊天系統,想了解的小夥伴可以自行去學習一下netty
一、一開始是導包,我是匯入這三個包
二、開啟伺服器,話不多說直接上程式碼,比較程式碼很簡單
DiscardServer.java 主函式開啟服務
public class DiscardServer implements Runnable{ private int port; private DiscardServer(int port) { this.port = port; } public void run() { EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1) EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); // (2) b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) // (3) .childHandler(new ChannelInitializer<SocketChannel>() { // (4) @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new DiscardServerHandler()); } }) .option(ChannelOption.SO_BACKLOG, 128) // (5) .childOption(ChannelOption.SO_KEEPALIVE, true); // (6) // Bind and start to accept incoming connections. Channel f = b.bind(port).sync().channel(); // (7) // Wait until the server socket is closed. // In this example, this does not happen, but you can do that to gracefully // shut down your server. f.closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port; if (args.length > 0) { port = Integer.parseInt(args[0]); } else { port = 1001; } new Thread( new DiscardServer(port)).start(); } }
DiscardServerHandler.java 負責通訊和訊息處理
public class DiscardServerHandler extends ChannelInboundHandlerAdapter { // (1) @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { // (2) ByteBuf in = (ByteBuf) msg; System.out.print(in.toString(io.netty.util.CharsetUtil.US_ASCII)); // 以靜默方式丟棄接收的資料 // ((ByteBuf) msg).release(); // (3) // ctx.writeAndFlush(firstMSG); // String name=in.toString(io.netty.util.CharsetUtil.US_ASCII); ApplicationContext.dealMessage(in.toString(io.netty.util.CharsetUtil.US_ASCII),ctx); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { ApplicationContext.writeMessage("ni hao a",ctx); System.out.println("this"+ctx.channel().remoteAddress().toString()); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (4) // 出現異常時關閉連線。 cause.printStackTrace(); ctx.close(); } @Override public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { super.channelWritabilityChanged(ctx); } }
ApplicationContext.java 負責客戶端儲存,訊息協議制度和處理,定義Map來儲存使用者ID和客戶端
public class ApplicationContext { private static Map<Integer, ChannelHandlerContext> onlineUsers = new HashMap<Integer, ChannelHandlerContext>();//儲存使用者客戶端訊息 private static void add(Integer uid, ChannelHandlerContext ctx) { onlineUsers.put(uid, ctx); } public static void remove(Integer uid) { onlineUsers.remove(uid); } private static ChannelHandlerContext getContext(Integer uid) { return onlineUsers.get(uid); } /** * 訊息處理、自定義協議 * @param message 訊息 * @param ctx 客戶端 */ static void dealMessage(String message, ChannelHandlerContext ctx) { String[] strings = message.split("#"); System.out.println(strings.length+" length"); //定義協議#號隔開陣列下標0:資料型別、1:接收端使用者ID、2:傳送端ID、3內容 if (strings.length != 4) return; switch (strings[0]) { case "0"://認證客戶端 add(Integer.valueOf(strings[2]), ctx); break; case "2"://指定使用者傳送 ChannelHandlerContext ctxTwo = getContext(Integer.valueOf(strings[1])); if (ctxTwo != null) writeMessage(message,ctxTwo); else writeMessage("is get out\n",ctx); break; } } /** * 傳送訊息 * @param message 訊息 * @param ctx 客戶端 */ static void writeMessage(String message, ChannelHandlerContext ctx) { ctx.writeAndFlush(Unpooled.buffer(message.getBytes().length).writeBytes(message.getBytes())); } }
接下來就大功告成了
三、除錯方式
連線伺服器,收到伺服器返回(ni hao a)的訊息, 馬上返回訊息繫結客戶端如0#1#2#3,及表示自己客戶端的id為2,其他客戶端可通過id來向自己傳送訊息,傳送訊息給其他客戶端如2#1#2#4,給id為1的客戶端傳送訊息4。
上面那個只是我簡單設定的一個協議,大家使用可以的話可以設定其他的協議或者資料格式json、XML等等