这几天看了一下MINA,学习了一下mina的技术。写了一些例子从普通的SOCKET通讯到MINA通讯,已经SOCKET client和mina做服务端通讯。下面贴出具体的代码
1.普通socket通讯
client.java
package test.socket;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/***********************************************************************
*
* client.java
* @copyright Copyright: 2009-2012
* @creator 周辉<br/>
* @create-time Aug 21, 2009 4:07:22 PM
* @revision $Id: *
***********************************************************************/
public class client {
private static final Log log = LogFactory.getLog(client.class);
private static int i = 0;
private Socket s;
private ObjectOutputStream out;
private ObjectInputStream in;
public client() throws IOException {
}
/**
* @param args
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
client c = new client();
c.talk();
}
/**
* 发送消息
* @param out
*/
public void sendMessage(Socket s) {
try {
out = new ObjectOutputStream(s.getOutputStream());
Message m = new Message();
m.setStatus(i);
m.setType(3);
m.setMsgBody("hello client");
i++;
out.writeObject(m);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void receiveMessage(Socket s) {
try {
in = new ObjectInputStream(s.getInputStream());
Message m;
m = (Message) in.readObject();
log.info("message::::" + m.getStatus() + "::" + m.getType()
+ "::" + m.getMsgBody());;
} catch (Exception e) {
e.printStackTrace();
}
}
public void talk() throws Exception {
while (true) {
try {
s = new Socket("localhost", 9988);
sendMessage(s);
receiveMessage(s);
out.close();
in.close();
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch(Exception e){
e.printStackTrace();
}
finally {
try{
if(s!=null)s.close(); //断开连接
}catch (IOException e) {e.printStackTrace();}
}
}
}
}
功能客户端发送和接受服务端消息,休息5秒后在重复发送消息和接受消息
server.java
package test.socket;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/***********************************************************************
*
* Server.java
* @copyright Copyright: 2009-2012
* @creator 周辉<br/>
* @create-time Aug 21, 2009 4:01:54 PM
* @revision $Id: *
***********************************************************************/
public class Server {
private static final Log log = LogFactory.getLog(Server.class);
private ServerSocket socket;
private ObjectInputStream in;
private ObjectOutputStream out;
private static int i = 0;
public Server() throws Exception{
socket= new ServerSocket(9988);
}
/**
* @param args
*/
public static void main(String[] args) throws Exception {
Server s =new Server();
log.info("server is start");
s.talk();
}
/**
* 接受消息
* @param s
*/
public void receiveMessage(Socket s) {
try {
in = new ObjectInputStream(s.getInputStream());
Message m;
m = (Message) in.readObject();
log.info("message::::" + m.getStatus() + "::" + m.getType()
+ "::" + m.getMsgBody());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 发送消息
* @param out
*/
public void sendMessage(Socket s) {
try {
out = new ObjectOutputStream(s.getOutputStream());
Message m = new Message();
m.setStatus(i);
m.setType(3);
m.setMsgBody("hello server");
i++;
out.writeObject(m);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void talk()throws Exception{
while(true){
Socket socket=null;
try {
socket = this.socket.accept(); //等待客户连接
receiveMessage(socket);
sendMessage(socket);
out.close();
in.close();
} catch (RuntimeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
finally {
try{
if(socket!=null)socket.close(); //断开连接
}catch (IOException e) {e.printStackTrace();}
}
}
}
}
服务端接收消息后发送消息给客户端,之后进入柱塞状态等待新的连接
message.java
package test.socket;
import java.io.Serializable;
public class Message implements Serializable {
private int type;
private int status;
private String msgBody;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMsgBody() {
return msgBody;
}
public void setMsgBody(String msgBody) {
this.msgBody = msgBody;
}
}
后启动server.java 和client.JAVA 看运行结果控制台打印出相应收发数据
2 mina 传递字符串
先介绍一下MINA传递数据的方式.mina主要是通过1建立连接,2过滤 3.IoHandler业务处理 这3块
常用到SocketAccepter 相对于ServerSocket ,SocketConnector 相对于Socket 客户端
然后就多了一个数据过滤iofilter.最后的IoHandler 就是业务逻辑处理
MINA 提供了 IoHandlerAdapter 类,此类仅仅是实现了 IoHandler 接口,但并不做任何处理。
一个 IoHandler 接口中具有如下一些方法(摘自 MINA 的 API 文档):
void exceptionCaught (IoSession session, Throwable cause) 当接口中其他方法抛出异常未被捕获时触发此方法 |
void messageReceived (IoSession session, Object message) 当接收到客户端的请求信息后触发此方法. |
void messageSent (IoSession session, Object message) 当信息已经传送给客户端后触发此方法. |
void sessionClosed (IoSession session) 当连接被关闭时触发,例如客户端程序意外退出等等. |
void sessionCreated (IoSession session) 当一个新客户端连接后触发此方法. |
void sessionIdle (IoSession session, IdleStatus status) 当连接空闲时触发此方法. |
void sessionOpened (IoSession session) 详细信息可以参考相关的文档
HelloWorldClient.java (客户端连接和过滤,客户端启动类)
HelloWorldClientHandler.java(客户端业务逻辑处理类) |
package test.simple;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
/***********************************************************************
*
* HelloWorldClientHandler.java
* @copyright Copyright: 2009-2012
* @creator 周辉<br/>
* @create-time Aug 21, 2009 2:04:26 PM
* @revision $Id: *
***********************************************************************/
public class HelloWorldClientHandler extends IoHandlerAdapter {
// 当一个客端端连结进入时
private static final Log log = LogFactory
.getLog(HelloWorldServerHandler.class);
public void sessionOpened(IoSession session) throws Exception {
log.info("server : " + session.getRemoteAddress());
}
// 当一个客户端关闭时
public void sessionClosed(IoSession session) {
log.info("one server Disconnect !");
}
// 当客户端发送的消息到达时:
public void messageReceived(IoSession session, Object message)
throws Exception {
String s = (String) message;
// Write the received data back to remote peer
log.info("收到服务端发来的消息: " + s);
//session.write("zzzzz");
}
// 发送消息给客户机器
public void messageSent(IoSession session,Object message) throws Exception {
log.info("发送消息给服务端: " + message);
}
// 发送消息异常
public void exceptionCaught(IoSession session, Throwable cause) {
session.close();
}
// //sessiong空闲
// public void sessionIdle( IoSession session, IdleStatus status )
// {
// }
// 创建 session
public void sessionCreated(IoSession session) {
}
}
HelloWorldServer.java(服务端连接和过滤类,服务端启动类)
package test.simple;
import java.net.InetSocketAddress;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.SocketAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
/*******************************************************************************
*
* HelloWorldServer.java
*
* @copyright Copyright: 2009-2012
* @creator 周辉<br/>
* @create-time Aug 21, 2009 2:01:00 PM
* @revision $Id: *
******************************************************************************/
public class HelloWorldServer {
private static final Log log = LogFactory.getLog(HelloWorldServer.class);
/**
* @param args
*/
public static void main(String[] args) {
try {
// 创建一个非阻塞的Server端Socket,用NIO
NioSocketAcceptor acceptor = new NioSocketAcceptor();
// 创建接收数据的过滤器
DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
// 设定这个过滤器将一行一行(/r/n)的读取数据
chain.addLast("codec", new ProtocolCodecFilter(
new TextLineCodecFactory()));
// 设定服务器端的消息处理器:一个SamplMinaServerHandler对象,
acceptor.setHandler(new HelloWorldServerHandler());
// 服务器端绑定的端口
int bindPort = 9988;
// 绑定端口,启动服务器
acceptor.bind(new InetSocketAddress(bindPort));
log.info("Mina Server is Listing on:= " + bindPort);
} catch (Exception e) {
e.printStackTrace();
}
}
}
HelloWorldServerHandler.java(服务端业务处理类)
package test.simple;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
/*******************************************************************************
*
* HelloWorldServerHandler.java
*
* @copyright Copyright: 2009-2012
* @creator 周辉<br/>
* @create-time Aug 21, 2009 1:45:52 PM
* @revision $Id: *
******************************************************************************/
public class HelloWorldServerHandler extends IoHandlerAdapter {
// 当一个客端端连结进入时
private static final Log log = LogFactory
.getLog(HelloWorldServerHandler.class);
public void sessionOpened(IoSession session) throws Exception {
log.info("incomming client : " + session.getRemoteAddress());
}
// 当一个客户端关闭时
public void sessionClosed(IoSession session) {
log.info("one Clinet Disconnect !");
}
// 当客户端发送的消息到达时:
public void messageReceived(IoSession session, Object message)
throws Exception {
String s = (String) message;
// Write the received data back to remote peer
log.info("收到客户机发来的消息: " + s);
session.write("hello client");
}
// 发送消息给客户机器
public void messageSent(IoSession session, Object message) throws Exception {
log.info("发送消息给客户端: " + message);
}
// 发送消息异常
public void exceptionCaught(IoSession session, Throwable cause) {
session.close();
}
// //sessiong空闲
// public void sessionIdle( IoSession session, IdleStatus status )
// {
// }
// 创建 session
public void sessionCreated(IoSession session) {
}
}
好了客户端服务端代码都有了可以测试了,启动HelloWorldServer.java 和HelloWorldClient.java 可以看到客户服务端收发消息了。
将HelloWorldClientHandler.java 中
// 当客户端发送的消息到达时:
public void messageReceived(IoSession session, Object message)
throws Exception {
String s = (String) message;
// Write the received data back to remote peer
log.info("收到服务端发来的消息: " + s);
session.write("zzzzz");
}
session.write("zzzzz"); 放开后运行,客户端服务端不挺得收发消息。
原因分析。我们知道messageReceived 方法是“当接收到客户端的请求信息后触发此方法 ” 客户端首先发起消息 给服务端,服务端 messageReceived收到消息后又写数据了,客户端messageReceived消息收到数据也写数据,这样就形成
客户----服务-----客户---服务。。。。。。。。。不停的运行了。
我们想可不可以用MINA 做服务端,普通 socket做客户端呢?答案是肯定的
socketClient.java
package test.simple;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.DataOutputStream;
import java.io.DataInputStream;
import java.net.Socket;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import test.socket.Message;
/***********************************************************************
*
* socketClient.java
* @copyright Copyright: 2009-2012
* @creator 周辉<br/>
* @create-time Aug 22, 2009 6:32:03 PM
* @revision $Id: *
***********************************************************************/
public class socketClient {
private static final Log log = LogFactory.getLog(socketClient.class);
private static int i = 0;
private Socket s;
private DataOutputStream out;
private DataInputStream in;
public socketClient() throws IOException {
}
/**
* @param args
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
socketClient c = new socketClient();
c.talk();
}
/**
* 发送消息
* @param out
*/
public void sendMessage(Socket s) {
try {
out = new DataOutputStream(s.getOutputStream());
i++;
out.writeBytes("wwww\n");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void receiveMessage(Socket s) {
try {
in = new DataInputStream(s.getInputStream());
log.info("message::::" +in.readLine());;
} catch (Exception e) {
e.printStackTrace();
}
}
public void talk() throws Exception {
while (true) {
try {
s = new Socket("localhost", 9988);
sendMessage(s);
receiveMessage(s);
out.close();
in.close();
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch(Exception e){
e.printStackTrace();
}
finally {
try{
if(s!=null)s.close(); //断开连接
}catch (IOException e) {e.printStackTrace();}
}
}
}
}
在这里我只写了一个SOCKET短连接,即收发消息后SOCKET断开一次,线程过5秒又建立连接收发消息
注意点:
public void sendMessage(Socket s) {
try {
out = new DataOutputStream(s.getOutputStream());
i++;
out.writeBytes("wwww\n");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
该方法 out.writeBytes("wwww\n"); 一定要写上\n结束符号才算一条消息结束,因为HelloWorldClient.java
中的过滤 new TextLineCodecFactory() 需要/r/n一行一行读取。
启动HelloWorldServer.java和socketClient.java 这样就可以实现 JAVA socket 和MINA 服务端通信了
3、mina 传递对象
其中原理和传递字符串是一样的,这里就不多说了
client.java(客户端连接和过滤,客户端启动类)
package test.object;
import java.net.InetSocketAddress;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
/***********************************************************************
*
* client.java
* @copyright Copyright: 2009-2012
* @creator 周辉<br/>
* @create-time Aug 22, 2009 6:16:29 PM
* @revision $Id: *
***********************************************************************/
public class client {
private static final Log log = LogFactory.getLog(client.class);
/**
* @param args
*/
public static void main(String[] args) {
// Create TCP/IP connector.
NioSocketConnector connector = new NioSocketConnector();
// 创建接收数据的过滤器
DefaultIoFilterChainBuilder chain = connector.getFilterChain();
//设定这个过滤器将一行一行(/r/n)的读取数据
chain.addLast("myChin", new ProtocolCodecFilter(new
ObjectSerializationCodecFactory()));
//设定服务器端的消息处理器:一个SamplMinaServerHandler对象,
connector.setHandler(new ObjectClientHandler());
// Set connect timeout.
connector.setConnectTimeoutCheckInterval(30);
//连结到服务器:
try
{
ConnectFuture cf = connector.connect(new InetSocketAddress("localhost", 9988));
cf.awaitUninterruptibly();
cf.getSession().getCloseFuture().awaitUninterruptibly();
Message b= new Message();
b.setStatus(1);
b.setType(2);
b.setMsgBody("test clinet");
connector.broadcast(b);
}
catch(Exception e)
{
connector.dispose();
log.error("未能连接到服务器");
}
}
}
ObjectClientHandler.java(客户端业务逻辑处理类)
package test.object;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
/***********************************************************************
*
* ObjectClientHandler.java
* @copyright Copyright: 2009-2012
* @creator 周辉<br/>
* @create-time Aug 21, 2009 3:47:40 PM
* @revision $Id: *
***********************************************************************/
public class ObjectClientHandler extends IoHandlerAdapter {
// 当一个客端端连结进入时
private static final Log log = LogFactory
.getLog(ObjectClientHandler.class);
public void sessionOpened(IoSession session) throws Exception {
log.info("server : " + session.getRemoteAddress());
}
// 当一个客户端关闭时
public void sessionClosed(IoSession session) {
log.info("one server Disconnect !");
}
// 当客户端发送的消息到达时:
public void messageReceived(IoSession session, Object message)
throws Exception {
Message s = (Message) message;
// Write the received data back to remote peer
log.info("收到服务端发来的消息: " + s.getMsgBody()+"::"+s.getStatus()+"::"+s.getType());
// Message b= new Message();
// b.setStatus(1);
// b.setType(2);
// b.setMsgBody("test client");
// session.write(b);
}
// 发送消息给客户机器
public void messageSent(IoSession session,Object message) throws Exception {
Message s = (Message) message;
log.info("发送消息给服务端: " + s.getMsgBody()+"::"+s.getStatus()+"::"+s.getType());
}
// 发送消息异常
public void exceptionCaught(IoSession session, Throwable cause) {
session.close();
}
// //sessiong空闲
// public void sessionIdle( IoSession session, IdleStatus status )
// {
// }
// 创建 session
public void sessionCreated(IoSession session) {
}
}
Server.java(服务端连接和过滤类,服务端启动类)
package test.object;
import java.net.InetSocketAddress;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import test.simple.HelloWorldServer;
import test.simple.HelloWorldServerHandler;
/***********************************************************************
*
* Server.java
* @copyright Copyright: 2009-2012
* @creator 周辉<br/>
* @create-time Aug 21, 2009 3:52:21 PM
* @revision $Id: *
***********************************************************************/
public class Server {
private static final Log log = LogFactory.getLog(Server.class);
/**
* @param args
*/
public static void main(String[] args) {
try {
// 创建一个非阻塞的Server端Socket,用NIO
NioSocketAcceptor acceptor = new NioSocketAcceptor();
// 创建接收数据的过滤器
DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();
// 设定这个过滤器将一行一行(/r/n)的读取数据
chain.addLast("codec", new ProtocolCodecFilter(
new ObjectSerializationCodecFactory()));
// 设定服务器端的消息处理器:一个ObjectServerHandler对象,
acceptor.setHandler(new ObjectServerHandler());
// 服务器端绑定的端口
int bindPort = 9988;
// 绑定端口,启动服务器
acceptor.bind(new InetSocketAddress(bindPort));
log.info("Mina Server is Listing on:= " + bindPort);
} catch (Exception e) {
e.printStackTrace();
}
}
}
ObjectServerHandler.java(服务端业务处理类)
package test.object;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
/*******************************************************************************
*
* ObjectServerHandler.java
*
* @copyright Copyright: 2009-2012
* @creator 周辉<br/>
* @create-time Aug 21, 2009 3:46:52 PM
* @revision $Id: *
******************************************************************************/
public class ObjectServerHandler extends IoHandlerAdapter {
// 当一个客端端连结进入时
private static final Log log = LogFactory.getLog(ObjectServerHandler.class);
public void sessionOpened(IoSession session) throws Exception {
log.info("incomming client : " + session.getRemoteAddress());
}
// 当一个客户端关闭时
public void sessionClosed(IoSession session) {
log.info("one Clinet Disconnect !");
}
// 当客户端发送的消息到达时:
public void messageReceived(IoSession session, Object message)
throws Exception {
Message s = (Message) message;
// Write the received data back to remote peer
log.info("收到客户机发来的消息: " + s.getMsgBody() + "::" + s.getStatus() + "::"
+ s.getType());
Message b = new Message();
b.setStatus(1);
b.setType(2);
b.setMsgBody("test zhou");
session.write(b);
}
// 发送消息给客户机器
public void messageSent(IoSession session, Object message) throws Exception {
Message s = (Message) message;
log.info("发送消息给客户端: " + s.getMsgBody() + "::" + s.getStatus() + "::"
+ s.getType());
}
// 发送消息异常
public void exceptionCaught(IoSession session, Throwable cause) {
session.close();
}
// //sessiong空闲
// public void sessionIdle( IoSession session, IdleStatus status )
// {
// }
// 创建 session
public void sessionCreated(IoSession session) {
}
}
message.java 和1.中的一样,这里不贴出来了
启动Server.java 和client可以看运行效果了
java socket客户端传递对象给 MINA 服务端,在MINA 收消息 的时候没有消息打出就关闭连接了,还没有试验出来。
希望知道的朋友告诉一声。