我正在使用Java中的Netty NIO开发客户端和服务器通信系统。我的代码可以找到in the following repository。目前我有一台服务器和两台客户端,我正在从服务器向客户端发送信息,反之亦然。
我想知道的是,当我从服务器的第一个客户端收到消息时,如何将该消息发送到第二个客户端(以及从客户端2到客户端1的相反消息)。如何向特定客户发送消息?
我注意到我的问题出现了,因为我试图从服务器发送消息的方式。我在serverHandler中的代码如下:
for (Channel ch : channels1) {
responseData.setIntValue(channels1.size());
remoteAddr.add(ch.remoteAddress().toString());
future = ch.writeAndFlush(responseData);
//future.addListener(ChannelFutureListener.CLOSE);
System.out.println("the requested data from the clients are: "+requestData);
responseData1.setStringValue(requestData.toString());
future = ch.writeAndFlush(responseData1);
System.out.println(future);
}
默认情况下,我发送一条关于连接数的消息,但是当我从客户端1或2接收消息时,我想将它发送回2和1.所以我想在两者之间进行通信组件。如何从服务器发送到特定客户端?我不知道如何将消息发送回客户端。
答案 0 :(得分:7)
让我们描述解决问题的方法。
在服务器端接收数据时,请使用频道的远程地址(java.net.SocketAddress Channel.remoteAddress()
method)来识别客户端。
这种识别可以使用如下地图来完成:Map<SocketAddress, Client>
,其中Client
类或接口应包含相应的客户端连接(通道)关联上下文,包括其Channel
。请务必使地图保持最新:正确处理“客户连接”和“客户端连接”事件。
识别出客户端后,您可以使用客户端连接(通道)映射向客户端(当前发送客户端除外)发送相应的消息。
此外,我建议您使用Netty找到一个很好的聊天应用程序实现,并查看它。
让我们考虑服务器端实现,特别是ProcessingHandler
类的实现。
它已经通过将它们表示为通道组来管理活动通道:
static final ChannelGroup channels1 =
new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
当前实现处理«频道变为活动»事件以使频道组保持最新:
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
channels1.add(ctx.channel());
// ...
}
但这只是一半:有必要对称地处理«通道变为非活动»事件。实现应该如下:
@Override
public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
channels1.remove(ctx.channel());
}
要实现所需的行为,只需通过引入相应的检查来更新实现,如下所示:
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// ...
for (Channel ch : channels1) {
// Does `ch` represent the channel of the current sending client?
if (ch.equals(ctx.channel())) {
// Skip.
continue;
}
// Send the message to the `ch` channel.
// ...
}
// ...
}
Currently,ResponseData
类的功能不存在(未实现)。
要使客户端和服务器都正常工作,需要进行以下草稿更改。
ResponseData
课程:getStringValue
和toString
方法应予以纠正:
String getStringValue() {
return this.strValue;
}
@Override
public String toString() {
return intValue + ";" + strValue;
}
ResponseDataEncoder
类:它应该使用字符串值:
private final Charset charset = Charset.forName("UTF-8");
@Override
protected void encode(final ChannelHandlerContext ctx, final ResponseData msg, final ByteBuf out) throws Exception {
out.writeInt(msg.getIntValue());
out.writeInt(msg.getStringValue().length());
out.writeCharSequence(msg.getStringValue(), charset);
}
ResponseDataDecoder
类:它应该使用字符串值:
private final Charset charset = Charset.forName("UTF-8");
@Override
protected void decode(final ChannelHandlerContext ctx, final ByteBuf in, final List<Object> out) throws Exception {
ResponseData data = new ResponseData();
data.setIntValue(in.readInt());
int strLen = in.readInt();
data.setStringValue(in.readCharSequence(strLen, charset).toString());
out.add(data);
}
ClientHandler
类:它应该正确接收和处理消息:
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
final ResponseData responseData = (ResponseData) msg;
System.out.println("The message sent from the server " + responseData);
update.accept(responseData.getIntValue());
}
SecureChatServerHandler
class。