Mina長連線框架實現Android客戶端與伺服器端通訊
阿新 • • 發佈:2019-02-14
一、概述
Apache Mina Server 是一個網路通訊應用框架,也就是說,它主要是對基於TCP/IP、UDP/IP協議棧的通訊框架(當然,也可以提供JAVA 物件的序列化服務、虛擬機器管道通訊服務等),Mina 可以幫助我們快速開發高效能、高擴充套件性的網路通訊應用,Mina 提供了事件驅動、非同步(Mina 的非同步IO 預設使用的是JAVA NIO 作為底層支援)操作的程式設計模型。
二、伺服器端程式碼
MinaService.java
package com.czhappy.mina; import java.net.InetSocketAddress; import java.util.Date; import org.apache.mina.core.service.IoAcceptor; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IdleStatus; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory; import org.apache.mina.filter.logging.LoggingFilter; import org.apache.mina.transport.socket.nio.NioSocketAcceptor; public class MinaService { public static void main(String[] args) { IoAcceptor acceptor = new NioSocketAcceptor(); //新增日誌過濾器 acceptor.getFilterChain().addLast("logger", new LoggingFilter()); acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory())); acceptor.setHandler(new DemoServerHandler()); acceptor.getSessionConfig().setReadBufferSize(2048); acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10); try { acceptor.bind(new InetSocketAddress(9226)); } catch (Exception e) { e.printStackTrace(); } System.out.println("啟動服務"); } /** * @ClassName: DemoServerHandler * @Description: 負責session物件的建立和監聽以及訊息的建立和接收監聽 * @author chenzheng * @date 2016-12-9 下午3:57:11 */ private static class DemoServerHandler extends IoHandlerAdapter{ //伺服器與客戶端建立連線 @Override public void sessionCreated(IoSession session) throws Exception { System.out.println("伺服器與客戶端建立連線..."); super.sessionCreated(session); } @Override public void sessionOpened(IoSession session) throws Exception { System.out.println("伺服器與客戶端連線開啟..."); super.sessionOpened(session); } //訊息的接收處理 @Override public void messageReceived(IoSession session, Object message) throws Exception { // TODO Auto-generated method stub super.messageReceived(session, message); String str = message.toString(); Date date = new Date(); session.write(date.toString()); System.out.println("接收到的資料:"+str); } @Override public void messageSent(IoSession session, Object message) throws Exception { // TODO Auto-generated method stub super.messageSent(session, message); } @Override public void sessionClosed(IoSession session) throws Exception { // TODO Auto-generated method stub super.sessionClosed(session); } } }
三、Android客戶端程式碼
ConnectionConfig.java
package com.czhappy.minaclient; import android.content.Context; /** * Description:構建者模式 * User: chenzheng * Date: 2016/12/9 0009 * Time: 16:37 */ public class ConnectionConfig { private Context context; private String ip; private int port; private int readBufferSize; private long connectionTimeout; public Context getContext() { return context; } public String getIp() { return ip; } public int getPort() { return port; } public int getReadBufferSize() { return readBufferSize; } public long getConnectionTimeout() { return connectionTimeout; } public static class Builder{ private Context context; private String ip = "192.168.168.20"; private int port = 9226; private int readBufferSize = 10240; private long connectionTimeout = 10000; public Builder(Context context){ this.context = context; } public Builder setIp(String ip){ this.ip = ip; return this; } public Builder setPort(int port){ this.port = port; return this; } public Builder setReadBufferSize(int readBufferSize){ this.readBufferSize = readBufferSize; return this; } public Builder setConnectionTimeout(long connectionTimeout){ this.connectionTimeout = connectionTimeout; return this; } private void applyConfig(ConnectionConfig config){ config.context = this.context; config.ip = this.ip; config.port = this.port; config.readBufferSize = this.readBufferSize; config.connectionTimeout = this.connectionTimeout; } public ConnectionConfig builder(){ ConnectionConfig config = new ConnectionConfig(); applyConfig(config); return config; } } }
ConnectionManager.java
package com.czhappy.minaclient; import android.content.Context; import android.content.Intent; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import org.apache.mina.core.future.ConnectFuture; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory; import org.apache.mina.filter.logging.LoggingFilter; import org.apache.mina.transport.socket.nio.NioSocketConnector; import java.lang.ref.WeakReference; import java.net.InetSocketAddress; /** * Description: * User: chenzheng * Date: 2016/12/9 0009 * Time: 16:21 */ public class ConnectionManager { private static final String BROADCAST_ACTION = "com.commonlibrary.mina.broadcast"; private static final String MESSAGE = "message"; private ConnectionConfig mConfig; private WeakReference<Context> mContext; private NioSocketConnector mConnection; private IoSession mSession; private InetSocketAddress mAddress; public ConnectionManager(ConnectionConfig config){ this.mConfig = config; this.mContext = new WeakReference<Context>(config.getContext()); init(); } private void init() { mAddress = new InetSocketAddress(mConfig.getIp(), mConfig.getPort()); mConnection = new NioSocketConnector(); mConnection.getSessionConfig().setReadBufferSize(mConfig.getReadBufferSize()); mConnection.getFilterChain().addLast("logging", new LoggingFilter()); mConnection.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory())); mConnection.setHandler(new DefaultHandler(mContext.get())); mConnection.setDefaultRemoteAddress(mAddress); } /** * 與伺服器連線 * @return */ public boolean connnect(){ Log.e("tag", "準備連線"); try{ ConnectFuture future = mConnection.connect(); future.awaitUninterruptibly(); mSession = future.getSession(); SessionManager.getInstance().setSeesion(mSession); }catch (Exception e){ e.printStackTrace(); Log.e("tag", "連線失敗"); return false; } return mSession == null ? false : true; } /** * 斷開連線 */ public void disContect(){ mConnection.dispose(); mConnection=null; mSession=null; mAddress=null; mContext = null; Log.e("tag", "斷開連線"); } private static class DefaultHandler extends IoHandlerAdapter{ private Context mContext; private DefaultHandler(Context context){ this.mContext = context; } @Override public void sessionOpened(IoSession session) throws Exception { super.sessionOpened(session); } @Override public void messageReceived(IoSession session, Object message) throws Exception { Log.e("tag", "接收到伺服器端訊息:"+message.toString()); if(mContext!=null){ Intent intent = new Intent(BROADCAST_ACTION); intent.putExtra(MESSAGE, message.toString()); LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent); } } } }
MinaService.java
package com.czhappy.minaclient;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.HandlerThread;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
/**
* Description:
* User: chenzheng
* Date: 2016/12/9 0009
* Time: 17:17
*/
public class MinaService extends Service{
private ConnectionThread thread;
@Override
public void onCreate() {
super.onCreate();
thread = new ConnectionThread("mina", getApplicationContext());
thread.start();
Log.e("tag", "啟動執行緒嘗試連線");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
thread.disConnect();
thread=null;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
class ConnectionThread extends HandlerThread{
private Context context;
boolean isConnection;
ConnectionManager mManager;
public ConnectionThread(String name, Context context){
super(name);
this.context = context;
ConnectionConfig config = new ConnectionConfig.Builder(context)
.setIp("192.168.168.20")
.setPort(9226)
.setReadBufferSize(10240)
.setConnectionTimeout(10000).builder();
mManager = new ConnectionManager(config);
}
@Override
protected void onLooperPrepared() {
while(true){
isConnection = mManager.connnect();
if(isConnection){
Log.e("tag", "連線成功");
break;
}
try {
Log.e("tag", "嘗試重新連線");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void disConnect(){
mManager.disContect();
}
}
}
SessionManager.java
package com.czhappy.minaclient;
import android.util.Log;
import org.apache.mina.core.session.IoSession;
/**
* Description:
* User: chenzheng
* Date: 2016/12/9 0009
* Time: 17:50
*/
public class SessionManager {
private static SessionManager mInstance=null;
private IoSession mSession;
public static SessionManager getInstance(){
if(mInstance==null){
synchronized (SessionManager.class){
if(mInstance==null){
mInstance = new SessionManager();
}
}
}
return mInstance;
}
private SessionManager(){}
public void setSeesion(IoSession session){
this.mSession = session;
}
public void writeToServer(Object msg){
if(mSession!=null){
Log.e("tag", "客戶端準備傳送訊息");
mSession.write(msg);
}
}
public void closeSession(){
if(mSession!=null){
mSession.closeOnFlush();
}
}
public void removeSession(){
this.mSession=null;
}
}
MinaTestActivity.java
package com.czhappy.minaclient;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
/**
* Description:
* User: chenzheng
* Date: 2016/12/9 0009
* Time: 18:01
*/
public class MinaTestActivity extends AppCompatActivity implements View.OnClickListener{
private TextView start_service_tv, send_tv, receive_tv;
private MessageBroadcastReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mina_test);
initView();
registerBroadcast();
}
private void registerBroadcast() {
receiver = new MessageBroadcastReceiver();
IntentFilter filter = new IntentFilter("com.commonlibrary.mina.broadcast");
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter);
}
private void initView() {
receive_tv = (TextView) this.findViewById(R.id.receive_tv);
start_service_tv = (TextView) this.findViewById(R.id.start_service_tv);
start_service_tv.setOnClickListener(this);
send_tv = (TextView) this.findViewById(R.id.send_tv);
send_tv.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.start_service_tv:
Log.e("tag", "點選啟動服務");
Intent intent = new Intent(this, MinaService.class);
startService(intent);
break;
case R.id.send_tv:
Log.e("tag", "點擊發送訊息");
SessionManager.getInstance().writeToServer("hello123");
break;
}
}
private void unregisterBroadcast(){
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
}
@Override
protected void onDestroy() {
super.onDestroy();
stopService(new Intent(this, MinaService.class));
unregisterBroadcast();
}
private class MessageBroadcastReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
receive_tv.setText(intent.getStringExtra("message"));
}
}
}
四、執行結果
1.點選啟動服務,觀察客戶端是否與伺服器端連線成功;
2.點擊發送訊息,觀察訊息是否傳送成功,如果失敗判斷失敗在哪一步。
客戶端執行結果:
伺服器端執行結果:
五、原始碼下載