tcp長連接+后台service+異步socket實例


總結一下后台服務編程,以及socket實現是一些注意事項。

1,service的生命周期:

//startService() 啟動Service
其生命周期為context.startService() ->onCreate()- >onStart()->Service running-->context.stopService() | ->onDestroy() ->Service stop 
//對於bindService()啟動Service:
context.bindService()->onCreate()->onBind()->Service running-->onUnbind() -> onDestroy() ->Service stop

 

2,怎么拿到service實例(binder接口)

3,startService()及bindService()使用

4,socket的accept,read,write阻塞解決

好吧,直接上代碼

GamepadSocketServer.java

package com.example.gamepaddemo.gamepadserver;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URLDecoder;

import org.json.JSONException;
import org.json.JSONObject;


import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;

/**
 * @author zhouxueliang
 * 1、接收連接請求,控制手柄界面
 * 2、發送數據
 */
public class GamepadSocketServer extends Service {
    public static final int GAMEPAD_REQUEST_START_ACTIVITY = 0;
    public static final int GAMEPAD_REQUEST_STOP_ACTIVITY  = GAMEPAD_REQUEST_START_ACTIVITY +1;
    
    
    /**
     * 監聽端口
     */
    private static final int PORT = 24000; 
    
    /**
     * SocketServer開關標志
     */
    public boolean isSocketServerStarted = false;
    
    
    /**
     * 客戶端Socket
     */
    private Socket clientSocket = null;
    private DataInputStream cInputStream = null;
    private DataOutputStream cOutputStream = null;
    
    /**
     * Server Socket
     */
    private ServerSocket serverSocket = null;
    
    /**
     * 線程切換使用handler
     */
    private Handler workHandler = new Handler();
    
    /**
     * 界面回調handler
     */
    private Handler helperListener = null;
    
    /**
     * 服務啟動是啟動socket監聽
     */
    @Override
    public void onCreate() {    
        startSocketServer();
        super.onCreate();
    }
    
 
    /**
     * 服務銷毀是是停止socket監聽
     */
    @Override
    public void onDestroy() {
        stopSocketServer();
        helperListener = null;
        super.onDestroy();
    }
    
    /**
     * 啟動socket監聽
     */
    public void startSocketServer() {
        if (!isSocketServerStarted) {
            try {
                /**
                 * 啟動ServerSocket
                 */
                serverSocket = new ServerSocket(PORT);
                isSocketServerStarted = true;            
            } catch (IOException e) {
                e.printStackTrace();
            }
            
            
            /**
             * Accept Socket
             */
            new Thread(new AcceptRunnable()).start();
        }
    }
    
    
    /**
     * 停止socket監聽
     */
    public void stopSocketServer() {
        if (isSocketServerStarted && serverSocket != null) {
            try {
                isSocketServerStarted = false;    
                if (clientSocket !=null && !clientSocket.isClosed()) {
                    clientSocket.close();
                    clientSocket = null;
                }
                serverSocket.close();
                serverSocket = null;
            } catch (IOException e) {
                e.printStackTrace();
            }            
        }
    }    

    /**
     * 設置界面回調監聽者
     */
    public void setHelperListener(Handler listener) {
        helperListener = listener;
    }
    
    
    /**
     * Socket Accept 線程(非阻塞)
     */
    public class AcceptRunnable implements Runnable {
        @Override
        public void run() {
            while (isSocketServerStarted) {
                try {
                    /**
                     * 監聽連接, 阻塞
                     */
                    final Socket client  = serverSocket.accept();
                    
                    /**
                     * 回調主線程
                     */
                    workHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            onGetClient(client);
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                }    
            }
        }
    }
    
    
    /**
     * Socket read 線程(非阻塞)
     */
    public class RecieverRunnable implements Runnable {
        private boolean runnable = true;
        @Override
        public void run() {
            while (runnable) {
                String inputString = null;
                int len = 0;
                try {
                    /**
                     * 等待read數據包大小,阻塞
                     */
                    len = cInputStream.readInt();
                    
                    /**
                     * read到數據包大小,read數據,阻塞
                     */
                    if (len > 0) {
                        byte[] input = new byte[len];
                        int l = -1;
                        int readlen = 0;
                        while(len-readlen > 0 && (l = cInputStream.read(input, readlen , len-readlen)) != -1){
                            readlen += l;
                        }
                        inputString = URLDecoder.decode(new String(input), "UTF-8");
                    }
                    
                } catch (IOException e) {
                    runnable = false;
                    e.printStackTrace();
                }
                
                /**
                 * 解析請求
                 */
                final RequestInfo requestInfo = parseInputString(inputString);
                if (requestInfo != null) {
                    /**
                     * read請求,回調主線程
                     */
                    workHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            onGetRequest(requestInfo);
                        }
                    });
                }
            }
        }
    }
    
    
    /**
     * accept請求,回調主線程
     */
    private void onGetClient(Socket client) {    
        if(initClientSocket(client)==0) {
            ;
        }        
    }
    
    
    /**
     * read(request)請求,回調主線程
     */
    private void onGetRequest(RequestInfo info) {    
        if(info != null) {
            if (info.target.equals("GamepadRequest")) {
                if (info.type == 0) {
                    stopGamepadActivity(info);
                }
                else {
                    startGamepadActivity(info);
                }
            }
        }        
    }
    
    
    /**
     * 請求拉起界面
     */
    private void startGamepadActivity(RequestInfo info) {
        if (helperListener !=null) {
            Message message = helperListener.obtainMessage(GAMEPAD_REQUEST_START_ACTIVITY, info);
            helperListener.sendMessage(message);
        }
    }
    
    
    /**
     * 請求關閉界面
     */
    private void stopGamepadActivity(RequestInfo info) {
        if (helperListener !=null) {
            Message message = helperListener.obtainMessage(GAMEPAD_REQUEST_STOP_ACTIVITY, info);
            helperListener.sendMessage(message);
        }
    }
    
    
    /**
     * 往客戶端發送數據
     */
    public void respondMessage(JSONObject obj) {
        try {
            if (cOutputStream != null) {
                String utf8String = new String(obj.toString().getBytes(), "UTF-8");
                cOutputStream.writeInt(utf8String.getBytes().length);
                cOutputStream.write(utf8String.getBytes());
                cOutputStream.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    
    /**
     * 初始化客戶端數據
     */
    private int initClientSocket(Socket cSocket) {
        try {
            
            /**
             * 重置
             */
            if  (cInputStream != null) {
                cInputStream.close();
                cInputStream = null;
            }            
            if  (cOutputStream != null) {
                cOutputStream.close();
                cOutputStream = null;
            }
            if  (clientSocket != null) {
                clientSocket.close();
                clientSocket = null;
            }
            
            /**
             * 重設
             */
            clientSocket = cSocket;
            cInputStream = new DataInputStream(clientSocket.getInputStream());
            cOutputStream = new DataOutputStream(clientSocket.getOutputStream());
            new Thread(new RecieverRunnable()).start();
        } catch (IOException e) {
            e.printStackTrace();
            return -1;
        }
        return 0;
    }
    
    /**
     * 服務的Binder
     */
    public GamepadServerBinder mBinder = new GamepadServerBinder();    
    public class GamepadServerBinder extends Binder {        
        public GamepadSocketServer getService() {
            /**
             * 返回service實例
             */
            return GamepadSocketServer.this;
        }
    }
    
    /**
     * 綁定服務
     */
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }
    
    /**
     * 重新綁定服務
     */
    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
    }
    
    
    /**
     * 解析數據
     */
    private RequestInfo parseInputString(String inputString) {
        if (inputString != null && inputString.length() > 0) {
            JSONObject object = null;
            RequestInfo request = null;
            try {
                object = new JSONObject(inputString);
                if (object != null) {
                    request = new RequestInfo();
                    request.target = object.getString("target");
                    request.type = object.getInt("type");
                    request.peerId = object.getString("peerId");
                    request.pcClientVersion = object.getString("pcClientVersion");
                }
                return request;
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    
    /**
     * 請求數據結構
     */
    public static class RequestInfo {
        String target;
        int    type;
        String peerId;
        String pcClientVersion;
    }
}

GamepadServerHelper.java

package com.example.gamepaddemo.gamepadserver;


import java.lang.ref.WeakReference;

import org.json.JSONException;
import org.json.JSONObject;
import com.example.gamepaddemo.gamepadview.GamepadActivity;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;


/**
 * 負責界面與socket服務的交互
 * @author zhouxueliang
 */
public class GamepadServerHelper {
    private boolean isServiceStarted = false;
    
    /**
     * service
     */
    private GamepadSocketServer gamepadServer = null;

    private Context mContext = null;

    /** 單例  **/
    private static GamepadServerHelper instance;
    private static Object instanceLock = new Object();

public static GamepadServerHelper getInstance(Context context) { if (instance == null) { synchronized(instanceLock){
if (instance == null) {           
                instance
= new GamepadServerHelper(context);
            }
}
}
return instance; }
private GamepadServerHelper(Context context) { mContext = context; } /** * 監聽service回調 */ private MessageListener gamepadServerMessageListener = new MessageListener() { @Override public void handleMessage(Message msg) { switch (msg.what) { case GamepadSocketServer.GAMEPAD_REQUEST_START_ACTIVITY: { RequestInfo info = (RequestInfo)msg.obj; Intent intent = new Intent(new Intent(mContext, GamepadActivity.class)); intent.putExtra("type", info.type); mContext.startActivity(intent); } break; case GamepadSocketServer.GAMEPAD_REQUEST_STOP_ACTIVITY: { Intent intent = new Intent(new Intent(mContext, GamepadActivity.class)); intent.putExtra("type", 0); mContext.startActivity(intent); } break; default: break; } } }; private Handler helperHander = new StaticHandler(gamepadServerMessageListener); /** * ServiceConnection,獲取service實例 */ private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { gamepadServer = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { gamepadServer = ((GamepadSocketServer.GamepadServerBinder)service).getService(); gamepadServer.setHelperListener(helperHander); } }; /** * 啟動手柄服務 */ public synchronized void startService(){ if(!isServiceStarted) { isServiceStarted = true; Intent intent = new Intent(); intent.setClass(mContext, GamepadSocketServer.class); mContext.startService(intent); mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } } /** * 關閉手柄服務 */ public synchronized void stopService(){ if(isServiceStarted) { isServiceStarted = false; Intent intent = new Intent(); intent.setClass(mContext, GamepadSocketServer.class); mContext.unbindService(mConnection); mContext.stopService(intent); gamepadServer = null; } } /** * 發送消息 */ public void sendMessage(JSONObject obj) { gamepadServer.respondMessage(obj); } /** * 用來消除Handle可能導致的泄漏 * 原在Util里,鑒於項目獨立性,直接移植 */ public static class StaticHandler extends Handler { WeakReference<MessageListener> listener; /** * * @param listener * 必讀: 此listener必須由Activity實現該接口(推薦)或者是宿主Activity的類成員 : 這里是弱引用, * 不會增加變量的引用計數, 使用匿名變量會導致listener過早釋放(請參考此類的引用示例) */ public StaticHandler(MessageListener listener) { this.listener = new WeakReference<MessageListener>(listener); } public StaticHandler(Looper looper, MessageListener listener) { super(looper); this.listener = new WeakReference<MessageListener>(listener); } @Override public void handleMessage(Message msg) { MessageListener listener = this.listener.get(); if (listener != null) { listener.handleMessage(msg); } } } /** * 原在Util里,鑒於項目獨立性,直接移植 */ public interface MessageListener { public void handleMessage(Message msg); } }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM