Android设备分别作为客户端和服务端与PC通讯
背景简介
这是一项比较老旧的技术了,不过在一些特定的场合(例如:无网络),进行传输数据,使用这项技术还是很方便的。网上有好很多类似的文章,个人觉得都不是特别完整,正好公司最近有涉及这方面的功能需求,借此机会整理Android分别作为客户端和服务端的实现。
核心原理
其实Socket通信,最根本的就是,Socket客户端和Socket服务端通过输入流和输出流进行数据传输。
整体思路
1.通过广播,来监听USB状态及Socket状态。
2.建立Socket连接。
3.获取Socket对象中的输入流或输出流,实现数据的接收或发送。
4.释放资源,关闭连接。
代码讲解
使用Rxjava和线程池来进行异步处理,发挥Service的优势增加稳定性。虽然是个小的功能,不过我也进行了多层封装,是代码更加健壮,灵活。
1.创建广播监听类ConnectStateReceiver
根据不同场景,分别进行说明
//服务端在监听
private static final String ACTION_SERVER_LISTENING = "SocketServerListening";
//Socket连接成功
private static final String ACTION_CONNECT_SUCCESS = "SocketConnectSuccess";
//Socket连接失败
private static final String ACTION_CONNECT_FAIL = "SocketConnectFail";
//USB线连接状态
private static final String ACTION_USB_STATE = "android.hardware.usb.action.USB_STATE";
场景一,Android作为客户端,PC作为服务端:(要求Android设备与PC所处同一局域网内)
1.ACTION_USB_STATE :USB连接状态,系统自行发送。
2.ACTION_SERVER_LISTENING :PC的Socket服务端正在监听,PC发送。
3.ACTION_CONNECT_SUCCESS :Socket连接成功,PC发送。
4.ACTION_CONNECT_FAIL :Socket连接失败,PC发送。
场景二,Android作为服务端,PC作为客户端:
1.ACTION_USB_STATE :USB连接状态,系统自行发送。
2.ACTION_CONNECT_SUCCESS :Socket连接成功,Android发送。
3.ACTION_CONNECT_FAIL :Socket连接失败,Android发送。
如何处理接收到的通知:
String action = intent.getAction();
if (TextUtils.equals(action, ACTION_SERVER_LISTENING)) {
ToastUtil.showToast(context, "服务端开始监听");
LogUtil.e("服务端开始监听");
//连接服务端
SocketManager.getInstance().connectServer(context);
} else if (TextUtils.equals(action, ACTION_CONNECT_SUCCESS)) {
ToastUtil.showToast(context, "Socket连接成功");
LogUtil.e("Socket连接成功");
//1.初始化发送请求工具类
SendRequestUtil.getInstance().init(SocketManager.getInstance().getDataOutputStream());
//2.启动Service,接收消息
context.startService(new Intent(context, DataService.class));
} else if (TextUtils.equals(action, ACTION_CONNECT_FAIL)) {
ToastUtil.showToast(context, "Socket连接失败");
LogUtil.e("Socket连接失败");
} else if (TextUtils.equals(action, ACTION_USB_STATE)) {
boolean connectedState = intent.getBooleanExtra("connected", false);
if (connectedState) {
ToastUtil.showToast(context, "USB已连接,开始监听客户端");
LogUtil.e("USB已连接,开始监听客户端");
//开始监听
SocketManager.getInstance().acceptClient(context);
} else {
ToastUtil.showToast(context, "USB断开连接");
LogUtil.e("USB断开连接");
//1.关闭Service,停止接收消息
context.stopService(new Intent(context, DataService.class));
//2.释放socket
SocketManager.getInstance().close();
}
}
以上代码结合了两种场景,可以根据自己的需求,对代码进行适当删减。
2.建立Socket连接
根据不同场景,分别进行说明
场景一,Android作为客户端,PC作为服务端:(要求Android设备与PC所处同一局域网内)
收到PC端发来的“Socket服务端正在监听”通知(即ACTION_SERVER_LISTENING)后,进行连接操作:
public void connectServer(final Context context) {
mConnectDisposable = Observable.create(new ObservableOnSubscribe<Boolean>() {
@Override
public void subscribe(ObservableEmitter<Boolean> emitter) throws Exception {
Socket socket = connect();
if (socket != null) {
emitter.onNext(true);
} else {
emitter.onNext(false);
}
emitter.onComplete();
}
}).subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Boolean>() {
@Override
public void accept(Boolean aBoolean) throws Exception {
if (aBoolean) {
ToastUtil.showToast(context, "连接服务端成功");
mState = STATE_CONNECT_SUCCESSED;
} else {
ToastUtil.showToast(context, "连接服务端失败");
mState = STATE_CONNECT_FAILED;
//弹出Dialog,提示重新连接
}
}
});
}
private Socket connect() {
Socket socket = null;
try