android ipc 多个客户端,详解 Android IPC 机制(八)使用 Socket 实现进程间通信

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

Socket 也称为 “嵌套字”,是计算机网络中的概念,分为流式嵌套字(TCP)和用户数据报嵌套字(UDP)。

不同用户进程通过 Socket 进行通信也是一种 IPC 方式。

在使用 Socket 通信前应在 AndroidManifest 中声明权限:

1、服务端

我们需要一个 Service 作为服务端,声明如下:

android:name=".socket.SocketService"

android:enabled="true"

android:exported="true"

android:process=":remote" />

Socket 服务端在 Service 启动时,会建立 TCP 连接并监听 8688 端口。public class SocketService extends Service {

private static final String TAG = "SocketService";

private boolean isDestroyed = false;

private String[] messages = new String[]{

"你好啊,哈哈",

"请问你叫什么名字呀?",

"今天北京天气不错啊",

"你知道吗?我可是可以和多个人同时聊天的哦",

"给你讲个笑话吧:据说爱笑的人运气不会太差,不知道真假。"

};

public SocketService() {

}

@Override

public void onCreate() {

super.onCreate();

new Thread(new TCPServer()).start();

}

@Override

public IBinder onBind(Intent intent) {

return null;

}

@Override

public void onDestroy() {

isDestroyed = true;

super.onDestroy();

}

private class TCPServer implements Runnable {

@Override

public void run() {

ServerSocket serverSocket = null;

try {

serverSocket = new ServerSocket(8688);

} catch (IOException e) {

e.printStackTrace();

}

while (!isDestroyed) {

try {

final Socket client = serverSocket.accept();

Log.d(TAG, "accept");

new Thread() {

@Override

public void run() {

responseClient(client);

}

}.start();

} catch (IOException e) {

e.printStackTrace();

}

}

}

private void responseClient(Socket client) {

try {

// 接收客户端消息

BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));

// 响应客户端消息

PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true);

Log.d(TAG, "欢迎来到聊天室!");

out.println("欢迎来到聊天室!");

while (!isDestroyed) {

String line = in.readLine();

Log.d(TAG, "message from Client: " + line);

if (line == null) break;

int i = new Random().nextInt(messages.length);

String message = messages[i];

out.println(message);

Log.d(TAG, "response to Client: " + message);

}

out.close();

in.close();

client.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

当与客户端建立连接后,新建 Socket 客户端,接收消息并作出响应。

2、客户端

客户端部分首先启动 Socket 服务,并且在连接失败后会不断重新尝试连接。public class SocketActivity extends AppCompatActivity {

private static final String TAG = "SocketActivity";

private Button bt_send;

private EditText et_receive;

private TextView tv_message;

private PrintWriter mPrintWriter;

private Socket mClientSocket;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_socket);

initView();

Intent service = new Intent(this, SocketService.class);

startService(service);

new Thread() {

@Override

public void run() {

connectSocketServer();

}

}.start();

}

private void initView() {

et_receive = findViewById(R.id.et_receive);

bt_send = findViewById(R.id.bt_send);

tv_message = findViewById(R.id.tv_message);

bt_send.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

final String msg = et_receive.getText().toString();

//向服务器发送信息

if (!TextUtils.isEmpty(msg) && mPrintWriter != null) {

Log.d(TAG, "onClick: " + msg);

new Thread(new Runnable() {

@Override

public void run() {

mPrintWriter.println(msg);

}

}).start();

tv_message.setText(tv_message.getText() + "n" + "客户端:" + msg);

et_receive.setText("");

}

}

});

}

private void connectSocketServer() {

Socket socket = null;

while (socket == null) {

try {

//选择和服务器相同的端口8688

socket = new Socket("localhost", 8688);

mClientSocket = socket;

mPrintWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);

} catch (IOException e) {

SystemClock.sleep(1000);

}

}

try {

// 接收服务器端的消息

BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

while (!isFinishing()) {

final String msg = br.readLine();

if (msg != null) {

runOnUiThread(

new Runnable() {

@Override

public void run() {

tv_message.setText(tv_message.getText() + "n" + "服务端:" + msg);

}

}

);

}

}

mPrintWriter.close();

br.close();

socket.close();

} catch (IOException e) {

e.printStackTrace();

}

}

@Override

protected void onDestroy() {

if (mClientSocket != null) {

try {

mClientSocket.shutdownInput();

mClientSocket.close();

} catch (IOException e) {

e.printStackTrace();

}

}

super.onDestroy();

}

}

主要使用 socket.getOutputStream() 和 socket.getInputStream() 方法分别发送、接收服务端消息。

打印日志如下:

55d4f678c275806922a9ca07fa593ef6.png

最终效果如下:

b34165ce162d67b6a890747aa288333c.png

到这里把 Android IPC 通信的几种实现方式基本看了一遍,但是在 Binder 机制原理方面还有欠缺,后面再深入学习。参考资料

1、《Android开发艺术探索》 — 2.4.6 使用 Socket

2、Android IPC机制(五)用Socket实现跨进程聊天程序 | 刘望舒的博客

http://liuwangshu.cn/application/ipc/5-socket.html如果本文对您有所帮助,且您手头还很宽裕,欢迎打赏赞助我,以支付网站服务器和域名费用。

pay_alpha.min.png 您的鼓励与支持是我更新的最大动力,我会铭记于心,倾于博客。

本文链接:https://www.wshunli.com/posts/c9a2416c.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值