Android进程间通信:Socket

388 阅读2分钟

使Service作为服务端 跑在com.example.sockettest:remote的私有进程中

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.sockettest">

    <uses-permission android:name="android.permission.INTERNET"/>

    <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.SocketTest">
        <service
                android:name=".TCPServerService"
                android:enabled="true"
                android:exported="true"
                android:process=":remote">

        </service>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Socket服务端代码

package com.example.sockettest;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

import com.ethan.ethanutils.IOUtil;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;

public class TCPServerService extends Service {
    private static final String TAG = "Ethan";
    private final String[] mDefinedMessages = new String[]{"你好小姐姐", "你好小哥哥"};
    private boolean mIsServiceDestroyed = false;

    public TCPServerService() {
    }

    @Override
    public void onCreate() {
        new Thread(new TcpServer()).start();
        super.onCreate();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        mIsServiceDestroyed = true;
        super.onDestroy();
    }

    class TcpServer implements Runnable {

        @Override
        public void run() {
            ServerSocket serverSocket = null;
            try {
                serverSocket = new ServerSocket(10000);
                while (!mIsServiceDestroyed) {
                    Socket client = serverSocket.accept();
                    Log.i(TAG, "服务端连接成功");

                    // 当连接成功后 单独开一个线程去负责通信 原线程继续阻塞在accept() 这样使得服务器可以与多个客户端连接
                    new Thread(() -> {
                        responseClient(client);
                    }).start();
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (serverSocket != null)
                        serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        private void responseClient(Socket client) {
            BufferedReader br = null;
            PrintWriter pw = null;
            try {
                br = new BufferedReader(new InputStreamReader(client.getInputStream()));
                pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true);

                while (!mIsServiceDestroyed) {
                    // readLine()以换行符为分界 所以如果发来的消息没有换行符是接收不到的
                    String s = br.readLine();
                    Log.i(TAG, "服务端收到了消息: " + s);
                    // 约定以null作为结束符
                    if (s == null)
                        break;
                    String reply = mDefinedMessages[new Random().nextInt(mDefinedMessages.length)];
                    pw.println(reply);
                }

                // 如果客户端要求断开连接就会退出while
                Log.i(TAG, "服务端断开连接");
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (br != null)
                    IOUtil.closeStream(br);
                if (pw != null)
                    IOUtil.closeStream(pw);
                try {
                    client.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

MainActivity作为客户端,跑在com.example.sockettest进程中

Socket客户端代码

package com.example.sockettest;

import android.content.Intent;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.widget.Button;

import androidx.appcompat.app.AppCompatActivity;

import com.ethan.ethanutils.IOUtil;

import java.io.*;
import java.net.Socket;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "Ethan";
    Socket mClientSocket;
    PrintWriter pw;
    BufferedReader br;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this, TCPServerService.class);
        startService(intent);

        new Thread(this::connectTCPServer).start();

        Button sendMsg = findViewById(R.id.button);
        sendMsg.setOnClickListener((v) -> {
            new Thread(() -> {
                pw.println("你好服务器!");
            }).start();
        });
    }

    @Override
    protected void onDestroy() {
        try {
            // 丢弃当前流中没被接收的数据
            mClientSocket.shutdownInput();
            mClientSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        super.onDestroy();
    }

    private void connectTCPServer() {
        // 如果没创建成功就一直尝试创建
        while (mClientSocket == null) {
            try {
                mClientSocket = new Socket("localhost", 10000);
                pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(mClientSocket.getOutputStream())), true);

                Log.i(TAG, "客户端连接成功");
            } catch (IOException e) {
                SystemClock.sleep(1000);
                Log.w(TAG, "连接超时,等待重试...");
                e.printStackTrace();
            }
        }

        try {
            br = new BufferedReader(new InputStreamReader(mClientSocket.getInputStream()));
            // 只要没离开页面断开连接 就一直在这里循环读消息
            while (!this.isFinishing()) {
                String s = br.readLine();
                Log.i(TAG, "客户端收到了消息:" + s);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (pw != null)
                IOUtil.closeStream(pw);
            if (br != null)
                IOUtil.closeStream(br);
        }
    }
}

image.png