学习Netty有一个多星期,参考《Netty实战》敲了Echo C/S 代码,也学习了channelHandler等组件。不满足客户端服务器一对一聊天,所以寻思着自己实现一个客户端和客户端一对一聊天,消息由服务器转发。
如果有代码写的不合适的地方,还请评论指正。
《Netty实战》电子书下载地址
主要思路
服务器端
- 服务器端维护一个ChannelHandlerContext类型的数组,用来存储与服务器连接的各个channel的信息。 (思路来源于《Netty 实战》6.3.2)
- 最大连接数控制。设置一个变量为最大数,
- 服务器主动关闭连接。当检测到一个连接的客户端掉线或异常,服务器应主动关闭连接
- 服务器转发消息。通过ChannelHandlerContext类型的数组获得与之相连的channel信息,将服务器读到的消息写给另一个客户端
- 译码器解码器。使读写更加方便
- 为了便于调试,还附加了一些包含获取时间,服务器显示读取的消息等等函数
客户端
- 发送信息
- 读取信息
- 主动关闭连接
- 输入指定字符串时下线。由于是控制台程序,所以我设置输入“bye”或“再见”时,调用相关函数关闭连接
实现代码
服务器端
类结构
类名 | 说明 |
---|---|
ServerHandler | 继承ChannelInboundHandlerAdapter接口 |
Server | 引导服务器端 |
实现代码
ServerHandler类
继承ChannelInboundHandlerAdapter接口,重写一些方法,添加一些私有变量来存储和控制channel信息
//ServerHandler类
import java.net.InetSocketAddress;
import java.util.Calendar;
import java.util.Vector;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
@Sharable
public class ServerHandler extends ChannelInboundHandlerAdapter {
private static final int MAX_CONN = 2;//指定最大连接数
private int connectNum = 0;//当前连接数
//channelHandlerContext表
private Vector<ChannelHandlerContext> contexts = new Vector<>(2);
//获取当前时间
private String getTime() {
Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int date = c.get(Calendar.DATE);
int hour = c.get(Calendar.HOUR_OF_DAY);
int minute = c.get(Calendar.MINUTE);
int second = c.get(Calendar.SECOND);
return new String(year + "/" + month + "/" + date + " " + hour + ":" + minute + ":" + second);
}
/*
* 重写channelActive()方法
* 更新当前连接数
* 控制连接客户端的个数,超过则关闭该channel
* 更新contexts数组
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// TODO Auto-generated method stub
connectNum++;
//控制客户端连接数量,超过则关闭
if (connectNum > MAX_CONN) {
ctx.writeAndFlush(Unpooled.copiedBuffer("达到人数上限".getBytes()));
ctx.channel().close();
//当前连接数的更新放在channelInactive()里
}
//更新contexts
contexts.add(ctx);
//控制台输出相关信息
InetSocketAddress socket = (InetSocketAddress) ctx.channel().remoteAddress();
System.out.println(socket.getAddress().getHostAddress() + ":" + socket.getPort() + "已连接");
System.out.println("当前连接数:" &#