代码基于第二个例子,支持多客户端的连接,在线聊天。

主要思路:

  连接建立时,在服务器端,保存channel 对象,当有新的客户端加入时,遍历保存的channel集合,向其他客户端发送加入消息。

  当一个客户端发送消息时,在服务器端,遍历channel集合,判断是否为发送者,来修改发送内容,如:    XX说:  我说:

同样的:

server中的主程序和第二个例子类似

server中的initializer

 import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil; public class MyChatServerInitlalizer extends ChannelInitializer<SocketChannel> { @Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//解码器,根据分隔符来分割
pipeline.addLast(new DelimiterBasedFrameDecoder(4096, Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));//编码
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));//解码 pipeline.addLast(new MyChatServerHandler()); }
}

server中的handler

 import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor; public class MyChatServerHandler extends SimpleChannelInboundHandler<String> { //这个对象可以获取到所有的channel
private static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
} @Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
Channel channel = ctx.channel(); channelGroup.forEach(ch -> {
System.out.println("ii");
if(ch != channel) {
System.out.println("othor");
ch.writeAndFlush(channel.remoteAddress() + "发送的消息:" + msg + "\n");//发送消息出去的时候,这个\n,一定不能丢,不然发不出去
} else {
ch.writeAndFlush( "自己: " + msg + "\n");
}
}); //服务器接收到消息,相所有客户端 发送 消息
System.out.println("接收到 " + channel.remoteAddress() +" 客户端的消息:" + msg);
// //发送给其他客户端
// ctx.writeAndFlush("msg");
} @Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();//获取到连接
//告诉已有的其他连接
channelGroup.writeAndFlush("[服务器] - " + channel.remoteAddress() + " - 加入\n");
//再加入
channelGroup.add(channel);//把channel加到channelGroup
} @Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
channelGroup.writeAndFlush("[服务器] - " + channel.remoteAddress() + "已离开\n");
// channelGroup.remove(channel);//netty会自动将已经失去连接的channel,从channelGroup 中移除
} @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
System.out.println(channel.remoteAddress() + "上线了!");
} @Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
Channel channel = ctx.channel();
System.out.println(channel.remoteAddress() + "下线了!");
}
}

clien中的主程序

 import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader; public class MyChatClient {
public static void main(String[] args) throws InterruptedException, IOException {
//客户端只需要一个
EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); try{ Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup)
.channel(NioSocketChannel.class)
.handler(new MyChatInitlaizer());
ChannelFuture channelFuture = bootstrap.connect("localhost", 8899).sync(); Channel channel = channelFuture.channel(); //channelFuture.channel().writeAndFlush("first msg");//发送数据,其实应该写到handler的active方法中 BufferedReader br = new BufferedReader(new InputStreamReader( System.in));
for (;;) {//死循环来接收客户端的输入
channel.writeAndFlush(br.readLine() + "\r\n");
} // channelFuture.channel().closeFuture().sync();
}finally {
eventLoopGroup.shutdownGracefully();
} }
}

client中的initializer和服务器端的类似

client中的handle,只要简单输出就行。

05-14 13:29