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); } }