日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

简易 IM 双向通信电脑端 GUI 应用——基于 Netty、JavaFX、多线程技术等

發布時間:2024/4/13 java 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 简易 IM 双向通信电脑端 GUI 应用——基于 Netty、JavaFX、多线程技术等 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

簡易 IM 雙向通信電腦端 GUI 應用——基于 Netty、JavaFX、多線程技術等

  • 說明
  • 運行效果
  • 核心代碼
  • 完整代碼
  • 參考知識

說明

??這是一個使用 Netty 來實現 IM 雙向通信的 demo 項目。通信雙方的客戶端 GUI 界面均是使用 JavaFX 來實現的。

??本 demo 項目已完成的工作有:

  • 通信雙方可互為發送方、接收方。

  • 在文本框中,可以點擊 發送 按鈕來發送消息,也可以使用 Enter,而在文本中另起一行需要使用組合鍵 Ctrl + Enter 來完成。

  • 通信過程是由其它線程在后臺完成,不會阻塞 UI 線程。

  • 通信雙方的通信是使用 Netty 來實現的,已解決 Netty 傳輸過程中的半包、粘包問題。

  • 實現對 Java 對象的透明傳輸。

    通信時可以傳輸 Java 對象,而不限制為簡單的文本數據。在發送端、接收端可以借助數據載體,通過對 Java 對象的序列化和反序列化來實現對 Java 對象的透明傳輸。

  • 本項目使用的數據載體有:

    • JSON
  • 運行效果



    核心代碼

    • 客戶端核心代碼
    package org.wangpai.demo.im.client;import com.fasterxml.jackson.core.JsonProcessingException; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.PooledByteBufAllocator; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; 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.LengthFieldPrepender; import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.handler.codec.string.StringEncoder; import io.netty.util.CharsetUtil; import java.util.List; import lombok.Setter; import lombok.experimental.Accessors; import org.wangpai.demo.im.protocol.Message; import org.wangpai.demo.im.protocol.Protocol; import org.wangpai.demo.im.util.json.JsonUtil;/*** @since 2021-12-1*/ @Accessors(chain = true) public class Client {@Setterprivate String ip;@Setterprivate int port;private Channel channel;private EventLoopGroup workerLoopGroup = new NioEventLoopGroup();public Client start() {Bootstrap bootstrap = new Bootstrap();bootstrap.group(workerLoopGroup);bootstrap.channel(NioSocketChannel.class);// 設置接收端的 IP 和端口號,但實際上,自己作為發送端也會為自己自動生成一個端口號bootstrap.remoteAddress(ip, port);bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);bootstrap.handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {// 最外層編碼器。為了幫助接收端解決粘包、半包問題ch.pipeline().addLast(new LengthFieldPrepender(Protocol.HEAD_LENGTH));// 將 String 數據轉化為二進制數據ch.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8));// 將 Java 對象轉化為 String 數據(JSON 數據)ch.pipeline().addLast(new MessageToMessageEncoder<Message>() {@Overrideprotected void encode(ChannelHandlerContext ctx, Message message, List<Object> out)throws JsonProcessingException {out.add(JsonUtil.pojo2Json(message));}});}});ChannelFuture future = bootstrap.connect();future.addListener((ChannelFuture futureListener) -> {if (futureListener.isSuccess()) {System.out.println("客戶端連接成功"); // FIXME:日志} else {System.out.println("客戶端連接失敗"); // FIXME:日志}});try {future.sync();} catch (Exception exception) {exception.printStackTrace(); // FIXME:日志}this.channel = future.channel();return this;}public void send(Message message) {channel.writeAndFlush(message);}public void send(String msg) {var message = new Message();message.setMsg(msg);this.send(message);}public void destroy() {this.workerLoopGroup.shutdownGracefully();}private Client() {super();}public static Client getInstance() {return new Client();} }
    • 服務器端核心代碼
    package org.wangpai.demo.im.server;import com.fasterxml.jackson.core.JsonProcessingException; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.PooledByteBufAllocator; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; 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.LengthFieldBasedFrameDecoder; import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.string.StringDecoder; import io.netty.util.CharsetUtil; import java.util.List; import lombok.Setter; import lombok.experimental.Accessors; import org.wangpai.demo.im.protocol.Message; import org.wangpai.demo.im.protocol.Protocol; import org.wangpai.demo.im.util.json.JsonUtil; import org.wangpai.demo.im.view.MainFace;/*** @since 2021-12-1*/ @Accessors(chain = true) public class Server {@Setterprivate int port;@Setterprivate MainFace mainFace;private EventLoopGroup bossLoopGroup = new NioEventLoopGroup(1);private EventLoopGroup workerLoopGroup = new NioEventLoopGroup();public Server start() {ServerBootstrap bootstrap = new ServerBootstrap();bootstrap.group(this.bossLoopGroup, this.workerLoopGroup);bootstrap.channel(NioServerSocketChannel.class);bootstrap.localAddress(port);bootstrap.option(ChannelOption.SO_KEEPALIVE, true);bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);bootstrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {// 最外層解碼器。可解決粘包、半包問題ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(1024, 0,Protocol.HEAD_LENGTH, 0, Protocol.HEAD_LENGTH));// 將二進制數據解碼成 String 數據ch.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));// 將 String 數據(JSON 數據)解碼成 Java 對象ch.pipeline().addLast(new MessageToMessageDecoder<String>() {@Overrideprotected void decode(ChannelHandlerContext ctx, String msg, List<Object> out)throws JsonProcessingException {out.add(JsonUtil.json2Pojo(msg, Message.class));}});// 進行對轉化后的最終的數據的處理ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object obj) {mainFace.receive(((Message) obj).getMsg());}});}});try {ChannelFuture channelFuture = bootstrap.bind().sync();ChannelFuture closeFuture = channelFuture.channel().closeFuture();closeFuture.sync();} catch (Exception exception) {exception.printStackTrace(); // FIXME:日志} finally {this.workerLoopGroup.shutdownGracefully();this.bossLoopGroup.shutdownGracefully();}return this;}public void destroy() {this.workerLoopGroup.shutdownGracefully();this.bossLoopGroup.shutdownGracefully();}private Server() {super();}public static Server getInstance() {return new Server();} }

    完整代碼

    ??已上傳至 GitCode 中,可免費下載:https://gitcode.net/wangpaiblog/20211213-im_demo-netty_javafx

    參考知識

    • JavaFX 中使用多線程與保證 UI 線程安全:https://blog.csdn.net/wangpaiblog/article/details/120755930

    • 如何在 JavaFX 的 TextArea 實現回車發送信息而不換行,但組合鍵 Ctrl + Enter 換行:https://blog.csdn.net/wangpaiblog/article/details/121506912

    總結

    以上是生活随笔為你收集整理的简易 IM 双向通信电脑端 GUI 应用——基于 Netty、JavaFX、多线程技术等的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。