android之mina框架通訊學習
阿新 • • 發佈:2019-02-10
這幾天剛學期android,目前專案要求的客戶端是android平臺,所以要開始啃了....
伺服器與客戶端的通訊準備使用現有的開發框架,找了幾個----mina,google 的 protobuf,smack,androidpn,Netty...
這些框架都不錯,不過最終選擇的是apache的mina框架,主要是mina在網上的資料比較全,用的也比較廣泛,再就是也適合我專案以後的擴充套件加入SPRING\CXF\RESTFUL WEBSERVICE等
不廢話了,開始把目前學習的進度開始進行整理,方便自己以後進行查閱,也給其他入門的兄弟們 參考參考。
當然,最重要的是希望大家能夠提出並給與寶貴的經驗。
服務端程式碼:
package org.demo; import java.net.InetSocketAddress; import java.nio.charset.Charset; import org.apache.mina.common.IdleStatus; import org.apache.mina.common.IoAcceptor; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.filter.codec.textline.LineDelimiter; import org.apache.mina.filter.codec.textline.TextLineCodecFactory; import org.apache.mina.transport.socket.nio.NioSocketAcceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Demo1Server { private static Logger logger = LoggerFactory.getLogger(Demo1Server.class); private static int PORT = 8989; public static void main(String[] args) { IoAcceptor acceptor = null; try { // 建立一個非阻塞的server端的Socket acceptor = new NioSocketAcceptor(); // 設定過濾器(使用Mina提供的文字換行符編解碼器) acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset .forName("UTF-8"), LineDelimiter.WINDOWS.getValue(), LineDelimiter.WINDOWS.getValue()))); // 設定讀取資料的緩衝區大小 acceptor.getSessionConfig().setReadBufferSize(2048); // 讀寫通道10秒內無操作進入空閒狀態 acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10); // 繫結邏輯處理器 acceptor.setHandler(new Demo1ServerHandler()); // 繫結埠 acceptor.bind(new InetSocketAddress(PORT)); logger.info("服務端啟動成功... 埠號為:" + PORT); } catch (Exception e) { logger.error("服務端啟動異常....", e); e.printStackTrace(); } } }
邏輯處理:
package org.demo; import java.util.Date; import net.sf.json.JSONObject; import org.apache.mina.common.IdleStatus; import org.apache.mina.common.IoHandlerAdapter; import org.apache.mina.common.IoProcessor; import org.apache.mina.common.IoSession; import org.apache.mina.transport.socket.nio.NioProcessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Demo1ServerHandler extends IoHandlerAdapter{ public static Logger logger = LoggerFactory.getLogger(Demo1ServerHandler.class); /** * 這個方法當一個Session 物件被建立的時候被呼叫。對於TCP 連線來說,連線被接受的時候 * 呼叫,但要注意此時TCP 連線並未建立,此方法僅代表字面含義,也就是連線的物件 * IoSession 被建立完畢的時候,回撥這個方法。 * 對於UDP 來說,當有資料包收到的時候回撥這個方法,因為UDP 是無連線的。 */ @Override public void sessionCreated(IoSession session) throws Exception { logger.info("服務端與客戶端建立連線..."); } /** * 這個方法在連線被開啟時呼叫,它總是在sessionCreated()方法之後被呼叫。對於TCP 來 * 說,它是在連線被建立之後呼叫,你可以在這裡執行一些認證操作、傳送資料等。 */ @Override public void sessionOpened(IoSession session) throws Exception { logger.info("服務端與客戶端連線開啟..."); } /** * 接收到訊息時呼叫的方法,也就是用於接收訊息的方法,一般情況下,message 是一個 * IoBuffer 類,如果你使用了協議編解碼器,那麼可以強制轉換為你需要的型別。 */ @Override public void messageReceived(IoSession session, Object message) throws Exception { /* String msg = message.toString(); //讀取資料 logger.info("服務端接收到的資料為:" + msg+"客戶端ip:"+session.getLocalAddress()); if ("bye".equals(msg)) { // 服務端斷開連線的條件 session.close(); } Date date = new Date(); session.write(date);*/ JSONObject jsonObject = JSONObject.fromObject(message.toString()); String username; String sex; String qq; String score; String nickname; username = jsonObject.getString("username"); sex = jsonObject.getString("sex"); qq = jsonObject.getString("QQ"); score = jsonObject.getString("Min.score"); nickname = jsonObject.getString("nickname"); int state = login(username); String msg = "登入成功!"; if(state == 0){ msg = "登入失敗!"; } logger.info("使用者:" + username + msg); //模擬登陸 if ("bye".equals(nickname)) { // 服務端斷開連線的條件 session.close(); } //Date date = new Date(); session.write(state); } //驗證使用者名稱 與 密碼 public int login(String message){ if("sysadmin".equals(message)){ return 1; } return 0; } /** * 當傳送訊息成功時呼叫這個方法,注意這裡的措辭,傳送成功之後, * 也就是說傳送訊息是不能用這個方法的。 */ @Override public void messageSent(IoSession session, Object message) throws Exception { logger.info("服務端傳送資訊成功..."); } /** * 對於TCP 來說,連線被關閉時,呼叫這個方法。 * 對於UDP 來說,IoSession 的close()方法被呼叫時才會毀掉這個方法。 */ @Override public void sessionClosed(IoSession session) throws Exception { logger.info("服務端連線已經失效"); } /** * 這個方法在IoSession 的通道進入空閒狀態時呼叫,對於UDP 協議來說,這個方法始終不會 * 被呼叫。 */ @Override public void sessionIdle(IoSession session, IdleStatus status) throws Exception { logger.info("服務端進入空閒狀態..."); } /** * 這個方法在你的程式、Mina 自身出現異常時回撥,一般這裡是關閉IoSession。 */ @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { logger.error("服務端傳送異常...", cause); } }
客戶端程式碼:
package org.demo;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.mina.common.ConnectFuture;
import org.apache.mina.common.IoConnector;
import org.apache.mina.common.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.LineDelimiter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
/**
* @author wangmiao
* @version 建立時間:2012-4-24 下午10:57:53 簡單說明
*/
public class HelloWorld2 extends Activity {
private static Logger logger = LoggerFactory.getLogger(HelloWorld2.class);
private static String HOST = "192.168.1.100";
private static int PORT = 8989;
private static String LOGIN_NAME = "";
public HelloWorld2() {
}
Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
System.out.println(1);
/*
* new Thread() { public void run() { socketServer(); } }.start();
*/
Button btn = (Button) findViewById(R.id.button1);
btn.setOnClickListener(new OnClickListener() {
EditText name = (EditText) findViewById(R.id.username);
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//name.setText("sysadmin"); 設定初始值
final Handler myHandler = new Handler(){
int i = 0;
@Override
public void handleMessage(Message msg) { //該執行緒位於主執行緒
// TODO Auto-generated method stub
//如果該訊息是本程式所傳送的
if(msg.what == 0x1233){
//主執行緒裡面 顯示操作
i++;
showToast("第"+i+"次連線開始....");
}
}
};
//定義一個計時器,讓該計時器週期性的執行指定任務 TimerTask物件的本質就是啟動一條新執行緒
new Timer().schedule(new TimerTask()
{
@Override
public void run() {
//新啟動的執行緒無法訪問該Activity裡的元件
//所以需要通過Handler傳送訊息
// TODO Auto-generated method stub
Message msg = new Message();
msg.what = 0x1233;
//傳送訊息
myHandler.sendMessage(msg);
LOGIN_NAME = name.getText().toString();
//在子執行緒裡面傳送請求
socketServer();
}
},0,10000);
//
/*// 壓力測試 10s秒鐘 執行一次
while(true){
new Thread(){
public void run(){
socketServer();
}
}.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}*/
}
});
System.out.println(1000);
}
public void showToast(final String text) {
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), text,
Toast.LENGTH_SHORT).show();
}
});
}
public void socketServer() {
// 建立一個非阻塞的客戶端程式
System.out.println(2);
IoConnector connector = new NioSocketConnector();
// 設定連結超時時間
System.out.println(3);
connector.setConnectTimeout(5);
System.out.println(4);
// 新增過濾器
connector.getFilterChain().addLast(
"codec",
new ProtocolCodecFilter(new TextLineCodecFactory(Charset
.forName("UTF-8"), LineDelimiter.WINDOWS.getValue(),
LineDelimiter.WINDOWS.getValue())));
// 新增業務邏輯處理器類
connector.setHandler(new Demo1ClientHandler());
IoSession session = null;
try {
System.out.println(5);
System.out.println(HOST + "|" + PORT);
// 這裡是非同步操作 連線後立即返回
ConnectFuture future = connector.connect(new InetSocketAddress(
HOST, PORT));// 建立連線
System.out.println(6);
future.awaitUninterruptibly();// 等待連線建立完成
System.out.println(7);
session = future.getSession();// 獲得session
// session.setAttribute(arg0, arg1)
String jsonStr = "{\"people\":["
+ "{ \"firstName\": \"問你t\", \"lastName\":\"McLaughlin\",\"email\": \"aaaa\" } ,"
+ "{ \"firstName\": \"Brett\", \"lastName\":\"McLaughlin\",\"email\": \"aaaa\" } ,] } ";
JSONObject json = createJSONObject();
// 根據key返回一個字串
// //String username = json.getString("username");
// System.out.println("username==>"+username);
System.out.println(8);
session.write(json);// 傳送訊息
System.out.println(9);
session.getCloseFuture().awaitUninterruptibly();// 等待連線斷開
connector.dispose();
System.out.println(Demo1ClientHandler.ini);
showToast(Demo1ClientHandler.ini);
} catch (Exception e) {
showToast("客戶端連結異常,請檢查網路");
logger.error("客戶端連結異常...", e);
}
}
public static JSONObject createJSONObject() {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("username", LOGIN_NAME);
jsonObject.put("sex", "男");
jsonObject.put("QQ", "413425430");
jsonObject.put("Min.score", new Integer(99));
jsonObject.put("nickname", "夢中心境");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return jsonObject;
}
}
wangmiao 寫道
這裡客戶端運用了 Handler訊息的傳遞機制,主要是為了解決android應用的多執行緒問題--Android平臺不允許Activity新啟動的執行緒訪問該Activity裡的介面元件,這樣就會導致新啟動的執行緒無法改變介面元件的屬性值。 Handler類的主要作用有兩個:1.新啟動的執行緒中傳送訊息 2.線上程中獲取、處理訊息
具體的關於Handler類的的使用去看相關的幫助說明。
邏輯處理:
package org.demo;
import org.apache.mina.common.IdleStatus;
import org.apache.mina.common.IoHandlerAdapter;
import org.apache.mina.common.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Demo1ClientHandler extends IoHandlerAdapter {
private static Logger logger = LoggerFactory
.getLogger(Demo1ClientHandler.class);
static String ini = "";
@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
System.out.println(message);
System.out.println(11);
String msg = message.toString();
String info = "";
if ("1".equals(msg)) {
// session.close(); //使用者登入成功 關閉連線
info = "登入成功";
} else {
info = "登入失敗";
}
ini = info;
session.setAttribute("state", info);
session.close();
System.out.println(12);
// final HelloWorld h = new HelloWorld();
// h.DisplayToast(info);
logger.info("客戶端接收到的資訊為:" + msg);
}
@Override
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
logger.error("客戶端發生異常...", cause);
}
@Override
public void sessionCreated(IoSession arg0) throws Exception {
// TODO Auto-generated method stub
}
@Override
public void sessionIdle(IoSession arg0, IdleStatus arg1) throws Exception {
// TODO Auto-generated method stub
}
/**
* 這個方法在連線被開啟時呼叫,它總是在sessionCreated()方法之後被呼叫。對於TCP 來
* 說,它是在連線被建立之後呼叫,你可以在這裡執行一些認證操作、傳送資料等。
*/
@Override
public void sessionOpened(IoSession arg0) throws Exception {
logger.info("ok", "i am ready!");
System.out.println(6);
}
}