前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >进程间通信的方式之Scoket——实现与AI鬼才聊天

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

作者头像
103style
发布2022-12-19 13:48:08
2330
发布2022-12-19 13:48:08
举报

转载请以链接形式标明出处: 本文出自: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!

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

以上


`

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-11-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
  • 简介
  • 实现跨进程与AI鬼才聊天
    • 1.首先申明网络权限
      • 2.实现服务端代码
        • 3.实现客户端代码
          • 4.启动程序,开始和 AI鬼才聊天
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档