该教程可以帮助你使用MINA框架编写基于UDP的Socket应用程序。在这篇教程中,我们将编写一个server端程序,server可以通过连接该程序来展现client端程序的内存使用情况。现实中的很多程序都已经具备与该程序类似的功能,可以监控程序来内存使用情况。
MINA 2.0的最终版本还没有release,但是你可以下载最新的版本。如果你希望从trunk构建代码,可以参考开发者指南。
如上图所示,该server在端口18567监听,client端连接server端并向server端发送内存使用数据。在上图所展示应用中,共有两个client连接到了server。
我们可以在MINA的示例代的org.apache.mina.example.udp包下找到这些代码。对于每个实例,我们只需要关系MINA相关的代码。
要想构建该server,我们需要做如下操作:
第一步可以通过该程序片来实现:
NioDatagramAcceptor acceptor = new NioDatagramAcceptor(); acceptor.setHandler(new MemoryMonitorHandler(this));
这里,我们创建一个NioDatagramAcceptor来监听client端请求,并且设置它的IoHandler。变量"PORT"是一个int值。下一步我们家filter链中加入了一个logging filter。LoggingFilter是一个非常不错的记录日志的方式,它可以在很多节点处生成日志信息,这些热值能够展现出MINA框架的工作方式。
DefaultIoFilterChainBuilder chain = acceptor.getFilterChain(); chain.addLast("logger", new LoggingFilter());
下一步我们深入一下UDP传输所特有的代码。我们设置acceptor可以重用address。
DatagramSessionConfig dcfg = acceptor.getSessionConfig(); dcfg.setReuseAddress(true);acceptor.bind(new InetSocketAddress(PORT));
当然,最后一件事情是调用bind()方法来绑定端口。
Server端主要关心如下三个事件:
详细代码如下:
@Override public void sessionCreated(IoSession session) throws Exception { SocketAddress remoteAddress = session.getRemoteAddress(); server.addClient(remoteAddress); }
在session创建事件中,我们调用addClient()方法来增加一个Tab页。
@Override public void messageReceived(IoSession session, Object message) throws Exception { if (message instanceof IoBuffer) { IoBuffer buffer = (IoBuffer) message; SocketAddress remoteAddress = session.getRemoteAddress(); server.recvUpdate(remoteAddress, buffer.getLong()); } }
在message接收事件中,我们从接收到的消息中得到所关心的内存使用的数据;应用程序还需要发送响应信息。在这个方法中,处理消息和发送响应都是通过session完成的。
@Override public void sessionClosed(IoSession session) throws Exception { System.out.println("Session closed..."); SocketAddress remoteAddress = session.getRemoteAddress(); server.removeClient(remoteAddress); }
在session关闭事件中,我们需要删除对应的Tab页。
在这一节,我们将解释一下客户端代码。实现客户端我们需要进行如下操作:
我们从MemMonClient.java开始,可以在org.apache.mina.example.udp.client包下找到它。开始的几行代码非常简单:
connector = new NioDatagramConnector(); connector.setHandler( this ); ConnectFuture connFuture = connector.connect( new InetSocketAddress("localhost", MemoryMonitor.PORT ));
这里我们创建了一个NioDatagramConnector,设置了它的handler并且连接到server端。我们必须在InetSocketAddress对象中设定host,否则程序不能正常运行。该程序是在Windows XP环境下开发运行的,所以与其他环境可能存在差别。下一步我们等待确认client已经连接到server端,一旦连接建立,我们可以开始向server端发送数据。代码如下:
connFuture.addListener( new IoFutureListener(){ public void operationComplete(IoFuture future) { ConnectFuture connFuture = (ConnectFuture)future; if( connFuture.isConnected() ){ session = future.getSession(); try { sendData(); } catch (InterruptedException e) { e.printStackTrace(); } } else { log.error("Not connected...exiting"); } } });
这里我们在ConnectFuture对象中加入一个listener,当client连接到server端时,operationComplete方法将被回调,这时我们开始发送数据。我们通过调用sendData方法向server端发送数据,该方法如下:
private void sendData() throws InterruptedException { for (int i = 0; i < 30; i++) { long free = Runtime.getRuntime().freeMemory(); IoBuffer buffer = IoBuffer.allocate(8); buffer.putLong(free); buffer.flip(); session.write(buffer); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); throw new InterruptedException(e.getMessage()); } } }
该方法会在30秒内每秒向server端发送当前的剩余内存Cincinnati。你可以看到我们分配了一个足够大的IoBuffer来装载一个long型的变量。最后这个buffer被flipped并发送至server端。