进程间通信的方式之Scoket——实现与AI鬼才聊天

2022-12-19 13:48:08 浏览数 (2)

转载请以链接形式标明出处: 本文出自:103style的博客

《Android开发艺术探索》 学习记录

base on AndroidStudio 3.5.1


目录

  • 前言
  • 实现跨进程与AI鬼才聊天
  • 小结

简介

前面我们介绍了: 进程间通信基础介绍 通过AIDL介绍Binder的工作机制 通过 Bundle、文件共享、Messenger实现进程间通信 进程间通信的方式之AIDL 进程间通信的方式之ContentProvider

本文主要介绍进程间通信的方式之 Scoket。

Socket 也称之为 “套接字”,是网络通信中的概念,分 流式套接字 和 用户数据套接字,分别对应网络的传输控制层中的 TCP 和 UDP 协议。 TCP是面向连接的协议,提供双向通信功能,连接建立需要 “三次握手”,为了传输的稳定性,其本身提供了超时机制。 UDP是无连接的,提供不稳定的单向通信功能,也可以提供双向。 在性能上UDP有更好的效率,缺点就是不能保证数据正确传输,尤其是网络拥塞的情况下。

下面我们来演示一个通过Socket实现跨进程聊天的程序,Socket本身可以支持传输任意的字节流,我们这里仅传输文本信息。


实现跨进程与AI鬼才聊天

主要由 服务端 和 客户端组成,在服务端创建一个 TCP服务, 然后在客户端连接这个服务,然后开始相互聊天,来模仿一下“AI鬼才” 的对话:

代码语言:javascript复制
在吗?
在!
你好
你好!
能听懂汉语吗?
能听懂汉语!
真的吗?
真的!
1.首先申明网络权限
代码语言:javascript复制
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

然后注意一点在Android4.0 以上不能直接在UI线程进行网络访问。

2.实现服务端代码

步骤大致为:

  • 创建一个ServerSocket,响应客户端的连接,注意服务端和客户端为一对多关系。(TCPServer)
  • 处理“AI鬼才”聊天的逻辑. (responseClient(...))
代码语言:javascript复制
public class TCPServerService extends Service {
    public static int PORT = 10024;
    private static final String TAG = "TCPServerService";
    private boolean destroyed = false;
    public void onCreate() {
        new Thread(new TCPServer()).start();
        super.onCreate();
    }
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    @Override
    public void onDestroy() {
        destroyed = true;
        super.onDestroy();
    }
    private void responseClient(Socket client) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));
        PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true);
        pw.println("welcome to chat room!");
        while (!destroyed) {
            String s = br.readLine();
            if (TextUtils.isEmpty(s)) {
                SystemClock.sleep(1000);
                continue;
            }
            Log.e(TAG, "client send msg = "   s);
            //AI鬼才逻辑
            if (s.contains("吗?")) {
                s = s.replaceAll("吗?", "!");
            } else {
                char end = s.charAt(s.length() - 1);
                if (end < '0' || (end > '9' && end < 'A')) {
                    s = s.substring(0, s.length() - 1)   "!";
                } else {
                    s  = "!";
                }
            }
            if (s.contains("你")) {
                s = s.replaceAll("你", "我");
            }
            pw.println(s);
        }
        pw.close();
        br.close();
        client.close();
    }
    private class TCPServer implements Runnable {
        @Override
        public void run() {
            ServerSocket serverSocket = null;
            while (serverSocket == null) {
                try {
                    serverSocket = new ServerSocket(PORT);
                } catch (IOException e) {
                    Log.e(TAG, "establish tcp server failed, port ="   PORT);
                    PORT  ;
                    SystemClock.sleep(1000);
                    Log.e(TAG, "retry...");
                }
            }
            while (!destroyed) {
                try {
                    Socket client = serverSocket.accept();
                    Log.e(TAG, "erverSocket accepted");
                    new Thread(() -> {
                        try {
                            responseClient(client);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }).start();
                } catch (IOException e) {
                    Log.e(TAG, "serverSocket.accept error");
                    SystemClock.sleep(1000);
                }
            }
        }
    }
}

AndroidManifest.xml 中声明,配置为 :remote 进程。

代码语言:javascript复制
<manifest ...>
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application ... >
        <service
            android:name="socket.TCPServerService"
            android:process=":remote" />
    </application>
</manifest>
3.实现客户端代码

步骤为:

  • 启动服务端服务 startService(new Intent(this, TCPServerService.class))
  • 初始化Socket,然后定时去读服务端发的消息,注意要在非UI线程中初始化Socketinit()
  • 然后再界面上添加一个文本编辑和发送,注意发送要在非UI线程中执行sendMsg()
代码语言:javascript复制
public class SocketTestActivity extends AppCompatActivity {
    private static final String TAG = "SocketTestActivity";
    private Socket mClientSocket;
    private PrintWriter mPrintWriter;
    private EditText editText;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_socket);
        editText = findViewById(R.id.input);
        startService(new Intent(this, TCPServerService.class));
        init();
        findViewById(R.id.send).setOnClickListener(v -> new Thread(() -> sendMsg()).start());
    }
    private void init() {
        new Thread(() -> {
            try {
                initSocket();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
    }
    private void initSocket() throws IOException {
        Socket socket = null;
        while (socket == null) {
            try {
                socket = new Socket("localhost", TCPServerService.PORT);
                mClientSocket = socket;
                mPrintWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(mClientSocket.getOutputStream())), true);
                Log.e(TAG, "connect server success");
            } catch (IOException e) {
                SystemClock.sleep(1000);
                Log.e(TAG, "initSocket: connect fail, retry....");
            }
        }
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        while (!SocketTestActivity.this.isFinishing()) {
            String msg = bufferedReader.readLine();
            if (TextUtils.isEmpty(msg)) {
                SystemClock.sleep(1000);
                continue;
            }
            Log.e(TAG, "receive msg from server = "   msg);
        }
        Log.e(TAG, "chat quit");
        mPrintWriter.close();
        bufferedReader.close();
    }
    private void sendMsg() {
        String temp = editText.getText().toString();
        if (TextUtils.isEmpty(temp) || mPrintWriter == null) {
            return;
        }
        mPrintWriter.println(temp);
        editText.setText("");
    }
    @Override
    protected void onDestroy() {
        if (mClientSocket != null) {
            try {
                mClientSocket.shutdownInput();
                mClientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (mPrintWriter != null) {
            mPrintWriter.close();
        }
        super.onDestroy();
    }
}
4.启动程序,开始和 AI鬼才聊天
代码语言:javascript复制
receive msg from server = welcome to chat room!
client send msg = 123
receive msg from server = 123!
client send msg = Hi
receive msg from server = Hi!
client send msg = understand?
receive msg from server = understand?!
client send msg = Really?
receive msg from server = Really?!
client send msg = NICE
receive msg from server = NICE!

如果觉得不错的话,请帮忙点个赞呗。

以上


`

0 人点赞