Apache MINA是Apachel织的一个优U的项目。MINA是Multipurpose Infrastructure for NetworkApplications的羃写。它是一个网l应用程序框Ӟ用来帮助用户非常方便地开发高性能和高可靠性的|络应用E序。在本文中介l了 如何通过Apache Mina2.0来实现TCP协议长连接和短连接应用?br />
2、系l介l?br />
2.1pȝ框架
整个pȝ׃个服务端E序和两个客LE序l成。分别实现TCP长连接和短连接通信?br />
pȝ业务逻辑是一个客L与服务端建立长连接,一个客L与服务端建立短连接。数据从短连接客Ll过服务端发送到长连接客LQƈ从长q接客户端接收响应数据。当收到响应数据后断开q接?br />
pȝ架构囑֦下:
2.2处理程
pȝ处理程如下Q?br />
1Q? 启动服务端程序,监听8001?002端口?br />
2Q? 长连接客L向服务端8002端口建立q接Q服务端连接对象保存到׃n内存中。由于采用长q接方式Q连接对象是唯一的?br />
3Q? 短连接客L向服务端8001端口建立q接。徏立连接后创徏一个连接对象?br />
4Q? 短连接客Lq接成功后发送数据。服务端接收到数据后从共享内存中得到长连接方式的q接对象Q用此对象向长q接客户端发送数据。发送前短q接对象设ؓ长连接对象的属性倹{?br />
5Q? 长连接客L接收到数据后q回响应数据。服务端从长q接对象的属性中取得短连接对象,通过此对象将响应数据发送给短连接客L?br />
6Q? 短连接客L收到响应数据后,关闭q接?br />
3、服务端E序
3.1长连接服务端
服务启动
public class MinaLongConnServer {
private static final int PORT = 8002;
public void start()throws IOException{
IoAcceptor acceptor = new NioSocketAcceptor();
acceptor.getFilterChain().addLast("logger", new LoggingFilter());
acceptor.getFilterChain().addLast("codec", newProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
acceptor.setHandler(new MinaLongConnServerHandler());
acceptor.getSessionConfig().setReadBufferSize(2048);
acceptor.bind(new InetSocketAddress(PORT));
System.out.println("Listeningon port " + PORT);
}
}
//消息处理
public class MinaLongConnServerHandler extends IoHandlerAdapter {
private final Logger logger = (Logger) LoggerFactory.getLogger(getClass());
@Override
public void sessionOpened(IoSession session) {
InetSocketAddress remoteAddress = (InetSocketAddress)session.getRemoteAddress();
String clientIp = remoteAddress.getAddress().getHostAddress();
logger.info("LongConnect Server opened Session ID ="+String.valueOf(session.getId()));
logger.info("接收来自客户?nbsp;:" + clientIp + "的连?");
Initialization init = Initialization.getInstance();
HashMap<String, IoSession> clientMap =init.getClientMap();
clientMap.put(clientIp, session);
}
@Override
public void messageReceived(IoSession session, Object message) {
logger.info("Messagereceived in the long connect server..");
String expression = message.toString();
logger.info("Message is:" + expression);
IoSession shortConnSession =(IoSession) session.getAttribute("shortConnSession");
logger.info("ShortConnect Server Session ID ="+String.valueOf(shortConnSession.getId()));
shortConnSession.write(expression);
}
@Override
public void sessionIdle(IoSession session, IdleStatus status) {
logger.info("Disconnectingthe idle.");
// disconnect an idle client
session.close(true);
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) {
// close the connection onexceptional situation
logger.warn(cause.getMessage(), cause);
session.close(true);
}
}
3.2短连接服务端
服务启动
public class MinaShortConnServer {
private static final int PORT = 8001;
public void start()throws IOException{
IoAcceptor acceptor = new NioSocketAcceptor();
acceptor.getFilterChain().addLast("logger", new LoggingFilter());
acceptor.getFilterChain().addLast("codec", newProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
acceptor.setHandler(new MinaShortConnServerHandler());
acceptor.getSessionConfig().setReadBufferSize(2048);
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 3);
acceptor.bind(new InetSocketAddress(PORT));
System.out.println("Listeningon port " + PORT);
}
}
消息处理
public class MinaShortConnServerHandler
extends IoHandlerAdapter {
private final Logger logger = (Logger) LoggerFactory.getLogger(getClass());
@Override
public void sessionOpened(IoSession session) {
InetSocketAddress remoteAddress = (InetSocketAddress)session.getRemoteAddress();
logger.info(remoteAddress.getAddress().getHostAddress());
logger.info(String.valueOf(session.getId()));
}
@Override
public void messageReceived(IoSession session, Object message) {
logger.info("Messagereceived in the short connect server

");
String expression = message.toString();
Initialization init = Initialization.getInstance();
HashMap<String, IoSession> clientMap =init.getClientMap();
if (clientMap ==
null || clientMap.size() == 0) {
session.write("error");
}
else {
IoSession longConnSession =
null;
Iterator<String> iterator =clientMap.keySet().iterator();
String key = "";
while (iterator.hasNext()) {
key = iterator.next();
longConnSession = clientMap.get(key);
}
logger.info("ShortConnect Server Session ID :"+String.valueOf(session.getId()));
logger.info("LongConnect Server Session ID :"+String.valueOf(longConnSession.getId()));
longConnSession.setAttribute("shortConnSession",session);
longConnSession.write(expression);
}
}
@Override
public void sessionIdle(IoSession session, IdleStatus status) {
logger.info("Disconnectingthe idle.");
// disconnect an idle client
session.close(
true);
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) {
// close the connection onexceptional situation
logger.warn(cause.getMessage(), cause);
session.close(
true);
}
}
4、客LE序
4.1长连接客L
使用java.net.Socket来实现向服务端徏立连接。Socket建立后一直保持连接,从服务端接收到数据包后直接将原文q回?br />
public class TcpKeepAliveClient {
private String ip;
private int port;
private static Socket socket = null;
private static int timeout = 50 * 1000;
public TcpKeepAliveClient(String ip, int port) {
this.ip = ip;
this.port = port;
}
public void receiveAndSend() throws IOException {
InputStream input = null;
OutputStream output = null;
try {
if (socket == null || socket.isClosed() || !socket.isConnected()) {
socket = new Socket();
InetSocketAddress addr = new InetSocketAddress(ip, port);
socket.connect(addr, timeout);
socket.setSoTimeout(timeout);
System.out.println("TcpKeepAliveClientnew ");
}
input = socket.getInputStream();
output = socket.getOutputStream();
// read body
byte[] receiveBytes = {};// 收到的包字节数组
while (true) {
if (input.available() > 0) {
receiveBytes = new byte[input.available()];
input.read(receiveBytes);
// send
System.out.println("TcpKeepAliveClientsend date :" + new String(receiveBytes));
output.write(receiveBytes, 0, receiveBytes.length);
output.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("TcpClientnew socket error");
}
}
public static void main(String[] args) throws Exception {
TcpKeepAliveClient client = new TcpKeepAliveClient("127.0.0.1", 8002);
client.receiveAndSend();
}
}
4.2短连接客L
服务启动
public class MinaShortClient {
private static final int PORT = 8001;
public static void main(String[] args) throws IOException,InterruptedException {
IoConnector connector = new NioSocketConnector();
connector.getSessionConfig().setReadBufferSize(2048);
connector.getFilterChain().addLast("logger", new LoggingFilter());
connector.getFilterChain().addLast("codec", newProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));
connector.setHandler(new MinaShortClientHandler());
for (int i = 1; i <= 10; i++) {
ConnectFuture future = connector.connect(new InetSocketAddress("127.0.0.1", PORT));
future.awaitUninterruptibly();
IoSession session =future.getSession();
session.write(i);
session.getCloseFuture().awaitUninterruptibly();
System.out.println("result=" + session.getAttribute("result"));
}
connector.dispose();
}
}
消息处理
public class MinaShortClientHandler extends IoHandlerAdapter{
private final Logger logger = (Logger) LoggerFactory.getLogger(getClass());
public MinaShortClientHandler() {
}
@Override
public void sessionOpened(IoSession session) {
}
@Override
public void messageReceived(IoSession session, Object message) {
logger.info("Messagereceived in the client..");
logger.info("Message is:" + message.toString());
session.setAttribute("result", message.toString());
session.close(true);
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) {
session.close(true);
}
}
5、ȝ
通过本文中的例子QApache Mina在服务端可实现TCP协议长连接和短连接。在客户端只实现了短q接模式Q长q接模式也是可以实现的(在本文中q是采用传统的java Socket方式Q。两个服务端之间通过׃n内存的方式来传递连接对象也许有更好的实现方式?img src ="http://www.aygfsteel.com/paulwong/aggbug/399155.html" width = "1" height = "1" />
]]>