```
while(true){
//主线程死循环等待新连接到来
Socket socket = serverSocket.accept();
//为新的连接创建新的线程,
executor.submit(new ConnectIOnHandler(socket));
```
```
private static final StringDecoder DECODER = new StringDecoder();
private static final StringEncoder ENCODER = new StringEncoder();
...
//boss线程监听端口,worker线程负责数据读写
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup();
//辅助启动类
ServerBootstrap bootstrap = new ServerBootstrap();
try {
//设置线程池
bootstrap.group(bossGroup, workerGroup);
//设置socket工厂
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.handler(new LoggingHandler(LogLevel.INFO));
//设置管道工厂
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//获取管道
ChannelPipeline pipe = socketChannel.pipeline();
// Add the text line codec combination first,
pipe.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
// the encoder and decoder are static as these are sharable
//字符串编码器
pipe.addLast(DECODER);
//字符串解码器
pipe.addLast(ENCODER);
//业务处理类
pipe.addLast(new IMServerHandle());
}
});
//绑定端口
// Bind and start to accept incoming connections.
ChannelFuture f = bootstrap.bind(port).sync();
if (f.isSuccess()) {
Log.debug("server start success... port: " + port + ", main work thread: "
+ Thread.currentThread().getId());
}
等待服务端监听端口关闭
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} finally {
//优雅退出,释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
```
```
/***
* 面向IM通信操作的业务类
* @author xhj
*
*/
public class IMServerHandle extends SimpleChannelInboundHandler<String> {
/**
* user操作业务类
*/
private UserBiz userBiz = new UserBiz();
/***
* 消息操作的业务类
*/
private IMMessageBiz immessagebiz = new IMMessageBiz();
/***
* 处理接受到的String类型的JSON数据
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println(" get msg >> "+msg);
//把JSON数据进行反序列化
Request req = JSON.parseObject(msg, Request.class);
Response respon = new Response();
respon.setSendTime(System.currentTimeMillis());
//判断是否是合法的请求
if(req != null ) {
System.out.println("the req method >> "+req.getMethod());
//获取操作类型
if(req.getMethod() == IMProtocol.LOGIN) {
//获取要操作的对象
User user = JSON.parseObject(req.getBody(),User.class);
//设置返回数据的操作类型
respon.setMethod(IMProtocol.LOGIN);
//执行业务操作
boolean bl = userBiz.login(user);
if(bl) {//检验用户有效
//设置响应数据
respon.setBody("login ok");
//设置状态
respon.setStatus(0);
//登录成功将连接channel保存到Groups里
ChannelGroups.add(ctx.channel());
//将用户的uname
channelId进行绑定,服务器向指定用户发送消息的时候需要用到uname
channelId
ChannelGroups.putUser(user.getUname(), ctx.channel().id());
//发送广播通知某人登录成功了
userBiz.freshUserLoginStatus(user);
} else {//用户密码错误
//设置错误描述
respon.setErrorStr("pwd-error");
//设置状态描述码
respon.setStatus(-1);
}
//将Response序列化为json
msg = JSON.toJSONString(respon);
//发送josn
"\r\n"
ctx.writeAndFlush(msg+"\r\n");
} else if(req.getMethod() == IMProtocol.SEND) {
IMMessage immsg = JSON.parseObject(req.getBody(), IMMessage.class);
immsg.setSendTime(System.currentTimeMillis()); c
```
```
private BlockingQueue<Request> requests = new LinkedBlockingQueue<>();
/**
* String字符串解码器
*/
private static final StringDecoder DECODER = new StringDecoder();
/***
* String字符串编码器
*/
private static final StringEncoder ENCODER = new StringEncoder();
/**
* 客户端业务处理Handler
*/
private IMClientHandler clientHandler ;
/**
* 添加发送请求Request
* @param request
*/
public void addRequest(Request request) {
try {
requests.put(request);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 是否继续进行运行
*/
private boolean run = true;
public void run() {
//远程IP
String host = "172.20.10.7";
//端口号
int port = 10000;
//工作线程
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//辅助启动类
Bootstrap b = new Bootstrap(); // (1)
//设置线程池
b.group(workerGroup); // (2)
//设置socket工厂 不是ServerSocket而是Socket
b.channel(NioSocketChannel.class); // (3)
b.handler(new LoggingHandler(LogLevel.INFO));
//设置管道工厂
b.handler(new ChannelInitializer<SocketChannel>() {
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipe = ch.pipeline();
// Add the text line codec combination first,
pipe.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
// the encoder and decoder are static as these are sharable
//字符串解码器
pipe.addLast(DECODER);
//字符串编码器
pipe.addLast(ENCODER);
clientHandler = new IMClientHandler();
//IM业务处理类
pipe.addLast(clientHandler);
}
});
// Start the client.
ChannelFuture f = b.connect(host, port).sync(); // (5)
Channel ch = f.channel();
ChannelFuture lastWriteFuture = null;
while(run) {
//将要发送的Request转化为JSON String类型
String line = JSON.toJSONString(requests.take());
if(line != null && line.length() > 0) {//判断非空
// Sends the received line to the server.
//发送数据到服务器
lastWriteFuture = ch.writeAndFlush(line + "\r\n");
}
}
// Wait until all messages are flushed before closing the channel.
//关闭写的端口
if (lastWriteFuture != null) {
lastWriteFuture.sync();
}
} catch(Exception ex){
ex.printStackTrace();
} finally {
//优雅的关闭工作线程
workerGroup.shutdownGracefully();
}
}
/**
* 增加消息监听接受接口
* @param messgeReceivedListener
*/
public void addMessgeReceivedListener(MessageSender.MessgeReceivedListener messgeReceivedListener) {
clientHandler.addMessgeReceivedListener(messgeReceivedListener);
}
/***
* 移除消息监听接口
* @param messgeReceivedListener
*/
public void remove(MessageSender.MessgeReceivedListener messgeReceivedListener) {
clientHandler.remove(messgeReceivedListener);
}
```
Netty的client端实现和Server实现方式大同小异。比Server端要简要些了。少一个NIOEventLoop。在Bootstrap 的handle方法中增加ChannelInitializer初始化监听器,并增加了IMClientHandler的监听操作。其中IMClientHandler具体处理服务器返回的通信信息。
通过ChannelFuture 获取Channel,通过Channel在一个循环里发送请求。如果消息队列BlockingQueue非空的时候,获取Request并发送。以上发送,如何接受数据呢?接受到的json被反序列化直接变成了对象Response,对Response进行处理即可。
定义了一个消息接受到的监听接口。
```
public static interface MessgeReceivedListener {
public void onMessageReceived(Response msg);
public void onMessageDisconnect();
public void onMessageConnect();
}
```
在接口onMessageReceived方法里直接对获取成功的响应进行处理。
而服务器端对某个客户端进行发送操作,把Channel添加到ChannelGroup里,将uname和channelid对应起来。需要对某个用户发送消息的时候通过uname获取channelid,通过channelid从ChannelGroup里获取channel,通过channel发送即可。
具体操作如下:
```
public void transformMessage(IMMessage message) {
Channel channel = ChannelGroups.getChannel(ChannelGroups.getChannelId(message.getTo()));
if(channel != null && channel.isActive()) {
Response response = new Response();
response.setBody(JSON.toJSONString(message));
response.setStatus(0);
response.setMethod(IMProtocol.REV);
response.setSendTime(System.currentTimeMillis());
channel.writeAndFlush(JSON.toJSON(response)+"\r\n");
}
}
ChannelGroups
public class ChannelGroups {
private static final Map<String,ChannelId> userList = new ConcurrentHashMap();
private static final ChannelGroup CHANNEL_GROUP = new DefaultChannelGroup("ChannelGroups",
GlobalEventExecutor.INSTANCE);
public static void putUser(String uname,ChannelId id) {
userList.put(uname,id);
}
```
运行效果图。