Apache MINA是一個網絡應用程序框架,用來幫助用戶簡單地開發高性能和高可靠性的網絡應用程序。它提供了一個經過Java NIO在不一樣的傳輸例如TCP/IP和UDP/IP上抽象的事件驅動的異步API。java
Apache MINA 也稱爲:
● NIO 框架庫
● 客戶端服務器框架庫
● 一個網絡套接字庫
MINA雖然簡單可是仍然提供了全功能的網絡應用程序框架:
● 爲不一樣的傳輸類型提供了統一的API:
○ 經過Java NIO提供TCP/IP 和 UDP/IP支持
○ 經過RXTX提供串口通信(RS232)
○ In-VM管道通信
○ 你能實現你本身的API!
● 過濾器做爲一個擴展特性; 相似Servlet過濾器
● 低級和高級的API:
○ 低級: 使用字節緩存(ByteBuffers)
○ 高級: 使用用戶定義的消息對象(objects)和編碼(codecs)
● 高度定製化線程模型:
○ 單線程
○ 一個線程池
○ 一個以上的線程池(也就是SEDA)
● 使用Java 5 SSL引擎提供沙盒(Out-of-the-box) SSL · TLS · StartTLS支持
● 超載保護和傳輸流量控制
● 利用模擬對象進行單元測試
● JMX管理能力
● 經過StreamIoHandler提供基於流的I/O支持
● 和知名的容器(例如PicoContainer、Spring)集成
● 從Netty平滑的遷移到MINA, Netty是MINA的前輩。linux
MINA 基本類的描述 :
IoAccepter 至關於網絡應用程序中的服務器端
IoConnector 至關於客戶端
IoSession 當前客戶端到服務器端的一個鏈接實例
IoHandler 業務處理邏輯
IoFilter 過濾器用於懸接通信層接口與業務層接口數據庫
要編寫和運行一個基於Apache MINA 2.0的程序,須要JDK 5.0以上版本,api
下面看一個domo:緩存
準備工做:服務器
mina-core-2.0.0-M6.jar
slf4j-api-1.5.2.jar網絡
在官網下載到mina,找出這幾個jar,添加到項目,session
服務端的代碼:框架
- public class MainFrame {
- private static final int PORT=5469;
-
- public static void main(String[] args) throws Exception{
- IoAcceptor acceptor=new NioSocketAcceptor();
- IoFilter filter=new ProtocolCodecFilter(new TextLineCodecFactory());
- acceptor.getFilterChain().addLast("vestigge", filter);
- acceptor.setHandler(new ServerHandler());
- acceptor.bind(new InetSocketAddress(PORT));
-
- System.out.println( "服務器正在監聽端口" + PORT +"...");
- }
- }
其中new ServerHandler()傳入的是實現了IoHandler接口的類,代碼以下:dom
- public class ServerHandler extends IoHandlerAdapter {
-
- @Override
- public void messageReceived(IoSession session, Object message)
- throws Exception {
- System.out.println("收到客戶端消息:" + message.toString());
- }
-
- @Override
- public void exceptionCaught(IoSession session, Throwable cause)
- throws Exception {
- System.out.println("服務器出現異常:" +cause);
- }
-
- }
重寫了父類中的messageReceived()和exceptionCaught()
通常在messageReceived()中對客戶端的請求進行業務,邏輯處理
下面在命令行用telnet測試一下,
若是是win 7沒有telnet,找到「打開或關閉Windows功能」 ,找到telnet客戶端和telnet服務端,勾選便可,
在命令行下輸入telnet 127.0.0.1 5469
而後再telnet窗口中輸入幾個字符回車,在控制檯能夠看到服務器成功收到了消息:
上節中經過一個簡單的例子,對Mina框架有了大致的瞭解,在上節的基礎上,看看 怎樣實現客戶端與服務端的通訊,
廢話很少說了,直接看代碼:
- public class Test {
-
- public static void main(String[] args) throws Exception{
- SocketConnector connector = new NioSocketConnector();
- IoFilter filter = new ProtocolCodecFilter(new TextLineCodecFactory());
- connector.getFilterChain().addLast("vestigge", filter);
- SocketAddress soketAddress = new InetSocketAddress("127.0.0.1", 5469);
- connector.setHandler(new ClientHandler());
- ConnectFuture future= connector.connect(soketAddress);
- future.join();
- if (!future.isConnected()) {
- System.out.println("鏈接服務器失敗");
- return;
- }
- future.getSession().write("hello");
- }
- }
能夠看到代碼與服務器端的代碼很像,也是很是的簡單,這就是框架的好處,不用再重複發明輪子,省了很多事,
- public class ClientHandler extends IoHandlerAdapter {
-
- public void messageReceived(IoSession arg0, Object message) throws Exception {
- System.out.println("收到服務器消息:" + message.toString());
- }
-
- public void exceptionCaught(IoSession arg0, Throwable arg1)
- throws Exception {
-
- }
- }
效果演示:
登錄界面的文章 http://www.linuxidc.com/Linux/2012-11/73437.htm
就不在重複了,直接看登錄的代碼,
用Mina傳遞字符串上節已經看過了,要實現傳遞對象,也很是簡單,只須要修改一下過濾器:
chain.addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));
在Android客戶端,登錄的Activity中:
- public class LoginActivity extends Activity{
- private EditText accountEditText;
- private EditText passwordEditText;
- private CheckBox remeberCheckBox;
-
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.activity_login);
- accountEditText=(EditText) findViewById(R.id.login_account);
- passwordEditText=(EditText) findViewById(R.id.login_password);
- remeberCheckBox=(CheckBox) findViewById(R.id.login_remember);
-
- findViewById(R.id.login_login).setOnClickListener(new OnClickListener(){
- public void onClick(View v) {
- if(accountEditText.getText().toString().equals("") ||
- passwordEditText.getText().toString().equals("")){
- Toast.makeText(LoginActivity.this, "帳號或密碼不能爲空!", Toast.LENGTH_SHORT).show();
- }else{
- User user=new User();
- user.setAccount(Integer.parseInt(accountEditText.getText().toString()));
- user.setPassword(passwordEditText.getText().toString());
- user.setOperation(VQMessageType.LOGIN);
- boolean b=new VQClient().sendLoginInfo(user);
-
- if(b){
- Toast.makeText(LoginActivity.this, "登錄成功!", Toast.LENGTH_SHORT).show();
- startActivity(new Intent(LoginActivity.this,MainActivity.class));
- }else{
- Toast.makeText(LoginActivity.this, "鏈接超時,登錄失敗!", Toast.LENGTH_SHORT).show();
- }
- }
- }
- });
- }
- }
能夠看到會調用VQClient這個類中的方法去發送登錄請求,VQClient的實現:
- public class VQClient {
- private static int PORT=5469;
- public boolean sendLoginInfo(User u){
- boolean b=false;
- System.setProperty("java.net.preferIPv6Addresses", "false");
- SocketConnector connector = new NioSocketConnector();
- connector.setConnectTimeoutMillis(300000);
- DefaultIoFilterChainBuilder chain=connector.getFilterChain();
- chain.addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));
- SocketSessionConfig cfg = connector.getSessionConfig();
- cfg.setUseReadOperation(true);
- IoSession session = connector.connect(new InetSocketAddress("10.0.2.2", PORT))
- .awaitUninterruptibly().getSession();
-
- session.write(u).awaitUninterruptibly();
-
- ReadFuture readFuture = session.read();
-
- if (readFuture.awaitUninterruptibly(30000,TimeUnit.SECONDS)) {
- VQMessage message = (VQMessage) readFuture.getMessage();
-
- if(message.getType().equals(VQMessageType.SUCCESS)){
- b= true;
- }
- } else {
- b= false;
- }
-
- session.close(true);
- session.getService().dispose();
- return b;
- }
- }
而後服務器端變化不大,在收到登錄請求後,會查詢數據庫,返回一個信息,來代表登錄成功或者失敗。
- public void messageReceived(IoSession session, Object message)
- throws Exception {
- User user=(User) message;
- if(user.getOperation().equals(VQMessageType.LOGIN)){
-
- boolean b=new UserDao().login(user.getAccount(), user.getPassword());
- if(b){
- System.out.println(">> ["+user.getAccount()+"] 上線了");
-
- VQMessage m=new VQMessage();
- m.setType(VQMessageType.SUCCESS);
- session.write(m);
- }
- }
- }
最後附上測試效果: