IPC 之 Socket 的使用
一、概述
我们知道在开发中,即时通讯、设备间的通信都是使用 Socket 实现,那当然用它来实现进程间通信更是不成问题。Socket 即套接字,是一个对 TCP / IP协议进行封装 的编程调用接口(API) 。通过Socket,我们才能在 Andorid 平台上通过 TCP/IP 协议进行开发。Socket 不是一种协议,而是一个编程调用接口(API),属于传输层(主要解决数据如何在网络中传输)。
Socket的使用类型主要有两种:
- 流套接字(
streamsocket) :基于TCP协议,采用 流的方式 提供可靠的字节流服务 - 数据报套接字(
datagramsocket):基于UDP协议,采用 数据报文 提供数据打包发送的服务
对于 TCP 和 UDP 的讲述,这里就不做说明。
二、Socket 实现 IPC
IPC 中两个重要角色: 客户端和服务端,示例工程仍旧是两个工程。我们先看服务端如何使用 Socket :
1. 服务端
服务端 Service 完整代码:
public class SocketService extends Service {
private String[] mDefinedMsg = new String[]{"你好啊,哈哈", "请问你叫什么名字啊?", "今天北京天气不错啊", "你知道吗,我可以和多个人同时聊天", "给你讲个笑话吧,爱笑的人运气不会太差。"};
int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
int KEEP_ALIVE_TIME = 1;
TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<Runnable>();
ExecutorService executorService = new ThreadPoolExecutor(NUMBER_OF_CORES, NUMBER_OF_CORES * 2, KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT, taskQueue);
private boolean isServiceDestroy = false;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
executorService.execute(new TcpServer());
}
@Override
public void onDestroy() {
super.onDestroy();
isServiceDestroy = true;
}
private class TcpServer implements Runnable {
@Override
public void run() {
ServerSocket serverSocket = null;
try {
//接听本地8688接口
serverSocket = new ServerSocket(8688);
} catch (IOException e) {
e.printStackTrace();
}
while (!isServiceDestroy && serverSocket != null) {
//接受客户端请求
try {
Socket client = serverSocket.accept();
executorService.execute(new TalkWithClient(client));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private class TalkWithClient implements Runnable {
private Socket socket;
TalkWithClient(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//用于接收客户端信息
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//用于向客户端发送信息
PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()), true);
out.println("欢迎来到聊天室");
while (!isServiceDestroy) {
String info = in.readLine();
if (info == null) { //客户端断开连接
break;
}
Log.i("CLIENT_INFO", info);
int i = new Random().nextInt(mDefinedMsg.length);
String msg = mDefinedMsg[i];
out.println(msg);
Log.i("Server_INFO", msg);
}
out.close();
in.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
在服务端通过循环的方式轮询是否有客户端接入,并判断服务一旦停止,停止循环。 accpet() 方法在没有客户端接入时,会阻塞当前线程,等到有客户端接入时会继续执行。
while (!isServiceDestroy && serverSocket != null) {
//接受客户端请求
try {
Socket client = serverSocket.accept();
executorService.execute(new TalkWithClient(client));
} catch (IOException e) {
e.printStackTrace();
}
}
TalkWithClient 是一个 Runnable 实现类,用来与客户端进行交互。通过循环的方式读取客户端传递过来的信息,代码中 readLine() 方法也会阻塞,直到客户端有消息过来继续执行。
while (!isServiceDestroy) {
String info = in.readLine();
if (info == null) { //客户端断开连接
break;
}
Log.i("CLIENT_INFO", info);
int i = new Random().nextInt(mDefinedMsg.length);
String msg = mDefinedMsg[i];
out.println(msg);
Log.i("Server_INFO", msg);
}
2. 客户端
客户端完整代码:
public class MainActivity extends AppCompatActivity {
private static final int MESSAGE_SOCKET_CONNECTED = 1;
private static final int MESSAGE_RECEIVE_NEW_MSG = 2;
int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
int KEEP_ALIVE_TIME = 1;
TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<Runnable>();
ExecutorService executorService = new ThreadPoolExecutor(NUMBER_OF_CORES, NUMBER_OF_CORES * 2, KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT, taskQueue);
private Socket mClientSocket;
private PrintWriter mPrintWriter;
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_SOCKET_CONNECTED:
btnSend.setEnabled(true);
break;
case MESSAGE_RECEIVE_NEW_MSG:
msgContainer.setText(String.format("%s%s", msgContainer.getText(), msg.obj));
break;
}
}
};
private TextView msgContainer;
private EditText etMsg;
private TextView btnSend;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
msgContainer = findViewById(R.id.msg_container);
etMsg = findViewById(R.id.msg);
btnSend = findViewById(R.id.btn_send);
btnSend.setEnabled(false);
executorService.execute(new Runnable() {
@Override
public void run() {
connectTCPServer();
}
});
}
@Override
protected void onDestroy() {
if (mClientSocket != null) {
try {
mClientSocket.shutdownInput();
mClientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
super.onDestroy();
}
public void sendMsg(View view) {
final String msg = etMsg.getText().toString();
if (!TextUtils.isEmpty(msg) && mPrintWriter != null) {
executorService.execute(new Runnable() {
@Override
public void run() {
mPrintWriter.println(msg);
}
});
etMsg.setText("");
String time = formatTimes(System.currentTimeMillis());
String showMsg = "client" + time + ":" + msg + "\n";
msgContainer.setText(String.format("%s%s", msgContainer.getText(), showMsg));
}
}
private void connectTCPServer() {
Socket socket = null;
while (socket == null) {
try {
socket = new Socket("localhost", 8688);
mClientSocket = socket;
mPrintWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(mClientSocket.getOutputStream())), true);
mHandler.sendEmptyMessage(MESSAGE_SOCKET_CONNECTED);
} catch (IOException e) {
SystemClock.sleep(1000);
//retry
}
}
//接收服务器消息
try {
BufferedReader br = new BufferedReader(new InputStreamReader(mClientSocket.getInputStream()));
while (!MainActivity.this.isFinishing()) {
String msg = br.readLine();
Log.i("CLIENT_RECEIVE", msg);
if (msg != null) {
String time = formatTimes(System.currentTimeMillis());
String showMsg = "server" + time + ":" + msg + "\n";
mHandler.obtainMessage(MESSAGE_RECEIVE_NEW_MSG, showMsg).sendToTarget();
}
}
mPrintWriter.close();
br.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@SuppressLint("SimpleDateFormat")
private String formatTimes(long millis) {
return "(" + new SimpleDateFormat("HH:mm:ss").format(new Date(millis)) + ")";
}
}
连接服务端:
connectTCPServer() 方法是用来连接服务端以及接收服务器消息,接收服务器消息仍然通过循环方式轮询。
注意:
Socket 实现 IPC 是网络操作,所以一定记得声明权限:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
最终能够进行传输数据,这里数据可以是任意数据,示例中只是传递了字符串。效果:

示例工程代码:
链接: https://pan.baidu.com/s/1Dq710Z4-vVsrNvgGUky09w密码: 52fv
IPC 之 Socket 的使用的更多相关文章
- Linux IPC BSD socket编程基础
头文件 #include<unistd.h> #include <sys/types.h> #include <sys/socket.h> #include< ...
- [置顶] 深入理解android之IPC机制与Binder框架
[android之IPC机制与Binder框架] [Binder框架.Parcel.Proxy-Stub以及AIDL] Abstract [每个平台都会有自己一套跨进程的IPC机制,让不同进程里的两个 ...
- Android IPC 结篇
一.概述 Android 的 IPC 方式有 Bundle .共享文件.AIDL .Messenger .ContentProvider .Socket ,我们在实现进程间通信时要选择哪一种方式来实现 ...
- Android利用LocalSocket实现Java端进程与C端进程之间的IPC
Android是建立在Linux之上的OS,在涉及到安全.网络协议.文件加密等功能时,往往需要通过C语言调用底层API来实现,而如何发出指令让C端执行我们想要的功能,并且在执行之后有返回结果呢,这就需 ...
- 大型项目必备IPC之Binder机制原理(一)
阿里P7Android高级架构进阶视频免费学习请点击:https://space.bilibili.com/474380680 摘要 Binder是Android系统进程间通信(IPC)方式之一.Li ...
- [转]Android Binder设计与实现 - 设计篇
摘要 Binder是Android系统进程间通信(IPC)方式之一.Linux已经拥有管道,system V IPC,socket等IPC手段,却还要倚赖Binder来实现进程间通信,说明Binder ...
- [转载] Android Bander设计与实现 - 设计篇
本文转载自: http://blog.csdn.net/chenxiancool/article/details/17454593 摘要 Binder是Android系统进程间通信(IPC)方式之一. ...
- 记一次Redis和NetMQ的测试
Redis是一个高速缓存K-V数据库,而NetMQ是ZeroMQ的C#实现版本,两者是完全不同的东西. 最近做游戏服务器的时候想到,如果选择一个组件来做服务器间通信的话,ZeroMQ绝对是一个不错的选 ...
- Android Bander设计与实现 - 设计篇
转自:http://blog.csdn.net/universus/article/details/6211589#t7 Binder Android IPC Linux 内核 驱动 摘要 Binde ...
随机推荐
- linux时间修改-hwclock和date
修改系统时间date 设定日期:date -s 月/日/年,例如设定日期为2018年12月1日,date -s 12/01/2018(年也可以是两位) 设定时间:date -s hh:mm:ss,例如 ...
- 把源码放到服务器部署webservice调用出错 MVC C#
C# WebService在本地调用正常,同样的代码布睹到服务器上总是调用报如下错误 Server Error in '/' Application. The resource cannot be f ...
- opencv学习之路(16)、膨胀腐蚀应用之走迷宫
一.分析 贴出应用图片以供直观了解 红色部分,因图而异(某些参数,根据图片的不同需要进行相应的修改) 二.代码 #include "opencv2/opencv.hpp" #inc ...
- kaggle竞赛_mnist_10%
主要是通过mnist了解kaggle的操作细节,最终这里的结果为: 引入必须的库¶ import pandas as pd import numpy as np import matplotlib ...
- NOIP 2016 换教室 (luogu 1850 & uoj 262) - 概率与期望 - 动态规划
题目描述 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程. 在可以选择的课程中,有 2n2n 节课程安排在 nn 个时间段上.在第 ii(1 \leq i \leq n1≤ ...
- python --- 21 MRO C3算法
一.python2.2之前用的是 经典类的MRO继承 ①深度递归继承 从左到右 ,一条路走到黑 ②广度继承 一层一层的继承 深度继承时 为 R 1 2 3 4 ...
- Web开发中B/S架构和C/S架构的区别
在web开发中有两种基本架构,即C/S架构和B/S架构那么这两种架构有什么区别呢?那么就一起来看看吧. C/S架构图: B/S架构图: C/S架构是 浏览/服务器端的交互,是早期的一种分布式架构,在该 ...
- SSM集成activiti6.0错误集锦(一)
项目环境 Maven构建 数据库:Orcle12c 服务器:Tomcat9 <java.version>1.8</java.version> <activiti.vers ...
- shell脚本中如何实现scp传输?
示例脚本如下: #! /bin/sh expect -c " spawn scp -r /home/jello/jello.txt jello@110.110.110.110:/home/j ...
- MetInfo V5.1 GetShell一键化工具
# 漏洞解析: config/config.inc.php $langoks = $db->get_one("SELECT * FROM $met_lang WHERE lang='$ ...