前几天学了Mina框架,发现作为一个网络通信的框架,确实比之前用socket好用太多,它很容易的实现了异步通信,学完之后被朋友问道是怎么实现异步通信的,我才发现,我学东西太浅了,没有钻研精神,带着这个疑问我在百度上搜了大神们的文章,后来才知道,Mina之所以能实现异步通信,是因为Mina是多线程的网络通信框架,Mina把这些线程封装起来,这样调用的时候就不会发生阻塞了!
// IoAcceptor acceptor = new NioSocketAcceptor();
言归正传,今天用Mina来写一个群聊聊天室。(明天再写私聊)
实现功能:
1.一个客户端发消息所有的客户端都可以接收
2.接收的同时,还要显示是哪个客户端发送的
3.有客户端退出聊天室的时,其他客户端也要接收到某个客户端退出的信息
一、接下来,代码展示
导包!导包!导包!
服务器端:
package mina_group_chat_0829;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.HashSet;
import java.util.Set;
public class MinaServer {
public static void main(String[] args) throws IOException {
//1.创建Ioservice实例
//创建一个非阻塞的server端的Socket
IoAcceptor acceptor = new NioSocketAcceptor();
//2.过滤链
acceptor.getFilterChain().addLast("logger",new LoggingFilter());
acceptor.getFilterChain().addLast("codec",new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
//处理器
//MyIoHandler()继承IoHandlerAdapter
//IoHandlerAdapter实现IoHandler接口
//接口不能new,所以需要他的实现子类,因为要实现不同的业务,所以要继承实现子类,重写方法
acceptor.setHandler(new MyIoHandler());
//连接
acceptor.bind(new InetSocketAddress(9999));
System.out.println("服务器开启");
}
}
class MyIoHandler extends IoHandlerAdapter {
private int count = 1;
Set<IoSession> sessions = new HashSet<IoSession>();
public MyIoHandler() {
super();
}
@Override
public void sessionCreated(IoSession session) throws Exception {
super.sessionCreated(session);
sessions.add(session);
//session.getRemoteAddress():获得当前通话的ip地址
System.out.println("有客户端接入:"+session.getRemoteAddress());
}
@Override
public void sessionOpened(IoSession session) throws Exception {
super.sessionOpened(session);
System.out.println("第"+count+"个客户端登录,address:"+session.getRemoteAddress());
count++;
}
@Override
public void sessionClosed(IoSession session) throws Exception {
super.sessionClosed(session);
broadcast(session.getRemoteAddress()+"会话通道关闭",session);
}
@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
super.sessionIdle(session, status);
broadcast(session.getRemoteAddress()+"会话休眠",session);
// System.out.println("服务器:会话休眠!"+session.getIdleCount(status));
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
super.exceptionCaught(session, cause);
broadcast(session.getRemoteAddress()+"有异常出现",session);
}
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
super.messageReceived(session, message);
//业务:如果客户端只输入quit,代表当前会话通道断开,不能进行通话了
String str = message.toString();
//trim():去掉str的前后空白格
if(str.trim().equalsIgnoreCase("quit"))
{
session.closeNow();
return;
}
System.out.println("服务器:接收信息..."+str);
//把接收到的信息广播出去
broadcast(str,session);
}
@Override
public void messageSent(IoSession session, Object message) throws Exception {
super.messageSent(session, message);
System.out.println("服务器发送消息:"+message);
}
@Override
public void inputClosed(IoSession session) throws Exception {
super.inputClosed(session);
System.out.println("服务器:输入关闭...");
}
//广播
public void broadcast(String message,IoSession exceptSession){
synchronized (sessions){
for(IoSession session:sessions){
if(session.isConnected()){//保持通信
if(session.equals(exceptSession)){
session.write("[you]"+message);
}else{
session.write("[客户端"+exceptSession.getRemoteAddress()+"]"+message);
}
}
}
}
}
}
客户端:
package mina_group_chat_0829;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
public class MinaClient {
public static void main(String[] args) throws IOException {
//1.连接器,
NioSocketConnector connector = new NioSocketConnector();
//2.设置过滤链
connector.getFilterChain().addLast("logger",new LoggingFilter());
connector.getFilterChain().addLast("codec",
new ProtocolCodecFilter(
new TextLineCodecFactory(
Charset.forName("UTF-8"))));
//3.设置处理器
connector.setHandler(new MyHandler());
//4.连接地址
ConnectFuture connect =
connector.connect(new InetSocketAddress("localhost",9999));
System.out.println("客户端已连接!");
int flag = 0;
while(flag==0){
//读取控制台的信息
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
String str = bf.readLine();
//通过连接获得会话,通过会话把内容传输到服务器
connect.getSession().write(str);
if(str.equals("quit")){
flag=1;
}
}
}
}
class MyHandler extends IoHandlerAdapter {
public MyHandler() {
super();
}
@Override
public void sessionCreated(IoSession session) throws Exception {
super.sessionCreated(session);
// System.out.println("客户端:会话被创建!");
}
@Override
public void sessionOpened(IoSession session) throws Exception {
super.sessionOpened(session);
// System.out.println("客户端:会话通道打开!");
}
@Override
public void sessionClosed(IoSession session) throws Exception {
super.sessionClosed(session);
// System.out.println("客户端:会话关闭!");
}
@Override
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
super.sessionIdle(session, status);
//System.out.println("客户端:会话休眠!");
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
super.exceptionCaught(session, cause);
//System.out.println("客户端:有异常出现!");
}
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
super.messageReceived(session, message);
System.out.println(message);
}
@Override
public void messageSent(IoSession session, Object message) throws Exception {
super.messageSent(session, message);
System.out.println("客户端:"+message);//只在服务器端显示
}
@Override
public void inputClosed(IoSession session) throws Exception {
super.inputClosed(session);
System.out.println("客户端:输入关闭!");
}
}
二、运行:
简易群聊室
为什么B站视频要审核这么久!!!上传视频真心不易!!
三、总结:
代码看完了,接下来我们一起看一下,这三个功能是怎么实现的?
1.一个客户端发消息所有的客户端都可以接收
这里自定义了一个broadcast(String message,Iosession exceptSession)方法,
每个通话通道被创建就被写入集合,List里面,然后通过broadcast(),遍历集合,
比对当前会话 exceptSession是不是集合里的当前会话,是的话就不广播给自己,
不是的话就广播出来!
2.接收的同时,还要显示是哪个客户端发送的
这里用到了session.getRemoteAddress()方法
3.有客户端退出聊天室的时,其他客户端也要接收到某个客户端退出的信息
同样用到broadcast()方法
代码可以直接复制,运行。复制不是目的,学习才是精髓。。。。算了,算了,求求大家点赞,关注我吧!