android socket 长连接
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实例
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;
public synchronized static GamepadServerHelper getInstance(Context context)
{
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);
}
}
声明:该文观点仅代表作者本人,入门客AI创业平台信息发布平台仅提供信息存储空间服务,如有疑问请联系rumenke@qq.com。
- 上一篇:没有了
- 下一篇:没有了
