簡易 IM 雙向通信電腦端 GUI 應用——基于 Netty、JavaFX、多線程技術等
說明
??這是一個使用 Netty 來實現 IM 雙向通信的 demo 項目。通信雙方的客戶端 GUI 界面均是使用 JavaFX 來實現的。
??本 demo 項目已完成的工作有:
通信雙方可互為發送方、接收方。
在文本框中,可以點擊 發送 按鈕來發送消息,也可以使用 Enter,而在文本中另起一行需要使用組合鍵 Ctrl + Enter 來完成。
通信過程是由其它線程在后臺完成,不會阻塞 UI 線程。
通信雙方的通信是使用 Netty 來實現的,已解決 Netty 傳輸過程中的半包、粘包問題。
實現對 Java 對象的透明傳輸。
通信時可以傳輸 Java 對象,而不限制為簡單的文本數據。在發送端、接收端可以借助數據載體,通過對 Java 對象的序列化和反序列化來實現對 Java 對象的透明傳輸。
本項目使用的數據載體有:
運行效果
核心代碼
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;
@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);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
));ch
.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8
));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("客戶端連接成功"); } else {System.out
.println("客戶端連接失敗"); }});try {future
.sync();} catch (Exception exception
) {exception
.printStackTrace(); }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;
@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
));ch
.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8
));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(); } 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
參考知識
總結
以上是生活随笔為你收集整理的简易 IM 双向通信电脑端 GUI 应用——基于 Netty、JavaFX、多线程技术等的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。