[英]Communication in Netty Nio java
我想在Netty nio中創建一個具有兩個客戶端和一個服務器的通信系統。 更具體地說,首先,我希望當兩個客戶端與服務器連接以從服務器發送消息時,之后能夠在兩個客戶端之間傳遞數據。 我正在使用此示例提供的代碼 。 我可以在這里找到我對代碼的修改: 鏈接
似乎serverHandler中的channelRead在第一個客戶端被連接時工作,因此它總是返回1但是當連接第二個客戶端時不會更改為2.當兩個客戶端連接到服務器時,如何從服務器正確檢查? 如何從客戶端的主要功能中動態讀取此值? 那么這是讓兩個客戶溝通的最佳方式?
EDIT1:顯然似乎客戶端服務正在運行並直接關閉,因此每次運行新的NettyClient時都會連接,但之后關閉連接。 所以計數器總是從0到1。 正如我在下面的評論中所建議的那樣,我在相同的端口使用telnet測試它,並且計數器似乎正常增加,但是,NettyClient服務沒有。
EDIT2:看來我得到的問題來自future.addListener(ChannelFutureListener.CLOSE);
它位於ProcessingHandler class
channelRead
中。 當我評論它似乎代碼工作。 但是,我不確定評論的后果是什么。 此外,我希望從客戶端的主要功能檢查返回消息何時是特定的兩個。 如何,我可以創建一個等待來自服務器的特定消息的方法,同時它阻止主要功能。
static EventLoopGroup workerGroup = new NioEventLoopGroup();
static Promise<Object> promise = workerGroup.next().newPromise();
public static void callClient() throws Exception {
String host = "localhost";
int port = 8080;
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.SO_KEEPALIVE, true);
b.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new RequestDataEncoder(), new ResponseDataDecoder(), new ClientHandler(promise));
}
});
ChannelFuture f = b.connect(host, port).sync();
} finally {
//workerGroup.shutdownGracefully();
}
}
我想在main函數內部調用方法並返回結果,當它為2時繼續使用主要功能。 但是,我無法在內部調用callClient,因為它將在同一個客戶端運行多次。
callBack();
while (true) {
Object msg = promise.get();
System.out.println("Case1: the connected clients is not two");
int ret = Integer.parseInt(msg.toString());
if (ret == 2){
break;
}
}
System.out.println("Case2: the connected clients is two");
// proceed with the main functionality
如何更新第一個客戶端的promise變量。 當我運行兩個客戶端時,對於第一個客戶端,我總是收到消息:
案例1:連接的客戶端不是兩個
似乎承諾沒有正常更新,而對於第二個客戶我總是收到:
案例2:連接的客戶端是兩個
如果我的內存是正確的,ChannelHandlerContext是每個通道一個,它可以在它的管道中有多個ChannelHandler。 您的channels變量是處理程序類的實例變量。 並為每個連接創建一個新的 ProcessingHandler實例。 因此,一旦初始化,每個將在channels
變量中具有一個且僅一個連接 - 它是為其創建的。
請參閱服務器代碼(NettyServer.java)中initChannel函數中的new ProcessingHandler()
)。
您可以將channels
變量設置為靜態,以便在ProcessingHandler實例之間共享它。 或者您可以在其他地方創建單個ProcessingHandler實例(例如,作為run()
函數中的局部變量),然后將該實例傳遞給addLast
調用而不是new ProcessingHandler()
。
為什么ChannelGroup頻道的大小始終是一個。 即使我連接更多客戶?
因為為每個新Channel
(客戶端)調用子ChannelInitializer
。 在那里,您正在創建ProcessingHandler
新實例,因此每個通道都會看到自己的ChannelGroup
實例。
解決方案1 - 通道屬性
使用屬性並將其與Channel
關聯。
在某處創建屬性(讓我們說在Constants
類中):
public static final AttributeKey<ChannelGroup> CH_GRP_ATTR =
AttributeKey.valueOf(SomeClass.class.getName());
現在,創建將由ProcessingHandler
的所有實例使用的ChannelGroup:
final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
在NettyServer中更新您的子ChannelInitializer
:
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(
new RequestDecoder(),
new ResponseDataEncoder(),
new ProcessingHandler());
ch.attr(Constants.CH_GRP_ATTR).set(channels);
}
現在您可以在處理程序中訪問ChannelGroup的實例,如下所示:
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
final ChannelGroup channels = ctx.channel().attr(Constants.CH_GRP_ATTR).get();
channels.add(ctx.channel());
這將起作用,因為每次新客戶端連接時,將使用與ChannelGroup
相同的引用調用ChannelInitializer。
解決方案2 - 靜態字段
如果將ChannelGroup
聲明為static,則所有類實例都將看到相同的ChannelGroup
實例:
private static final ChannelGroup channels =
new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
解決方案3 - 傳播共享實例
將參數引入ProcessingHandler
構造函數:
private final ChannelGroup channels;
public ProcessingHandler(ChannelGroup chg) {
this.channels = chg;
}
現在,你的NettyServer類中創建的實例ChannelGroup
,並將其傳播到ProcessingHandler構造函數:
final ChannelGroup channels = new
DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(
new RequestDecoder(),
new ResponseDataEncoder(),
new ProcessingHandler(channels)); // <- here
}
就個人而言,我會選擇第一個解決方案,因為
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.