美文网首页
Android 即时通信

Android 即时通信

作者: 古早味蛋糕 | 来源:发表于2023-04-13 11:30 被阅读0次

    一、简介
    虽然HTTP协议能够满足多数常见的接口交互,但是他属于短连接,每次调用完就自动断开连接,并且HTTP协议区分了服务端和客户端,双方的通信过程是单向的,只有客户端可以请求服务端,服务端无法主动向客户端推送信息,所以它不适合点对点的即时通信功能

    即时通信技术需要满足两方面的要求。一是长连接,以便在两台设备之间持续通信,避免频繁的连接断开操作,这样非常浪费资源。二是支持双向交流,既允许A设备主动向B设备发送消息,又允许B设备主动向A设备发送消息。

    可是Java 的Socket编程比较繁琐,不仅要自行编写线程通信与IO处理的代码,还要自己定义数据包的内部格式以及解编码,为此出现了第三方的Socket通信框架SocketIO,该框架提供了服务端和客户端的依赖包,大大简化了Socket通信的开发工作量。
    二、通过SocketIO传输文本消息
    在服务端集成SocketIO,要先引入相关jar包(服务端程序),

    netty-socketio-1.7.19.jar

    接着编写如下所示的main方法监听文本发送事件:

    public static void main(String[] args) {
        Configuration config = new Configuration();
        // 如果调用了setHostname方法,就只能通过主机名访问,不能通过IP访问
        //config.setHostname("localhost");
        config.setPort(9010); // 设置监听端口
        final SocketIOServer server = new SocketIOServer(config);
        // 添加连接连通的监听事件
        server.addConnectListener(client -> {
            System.out.println(client.getSessionId().toString()+"已连接");
        });
        // 添加连接断开的监听事件
        server.addDisconnectListener(client -> {
            System.out.println(client.getSessionId().toString()+"已断开");
        });
        // 添加文本发送的事件监听器
        server.addEventListener("send_text", String.class, (client, message, ackSender) -> {
            System.out.println(client.getSessionId().toString()+"发送文本消息:"+message);
            client.sendEvent("receive_text", "服务端发送而来的信息。");
        });
        // 添加图像发送的事件监听器
        server.addEventListener("send_image", JSONObject.class, (client, json, ackSender) -> {
            String desc = String.format("%s,序号为%d", json.getString("name"), json.getIntValue("seq"));
            System.out.println(client.getSessionId().toString()+"发送图片消息:"+desc);
            client.sendEvent("receive_image", json);
        });
    
        server.start(); // 启动Socket服务
    }
    

    然后服务端执行main方法即可启动Socket服务侦听。在客户端集成SocketIO的话,要先修改build.gradle,增加下面一行依赖配置:

    implementation 'io.socket:socket.io-client:1.0.1'

    接着使用SocketIO提供的Socket工具完成消息的收发操作,Socket对象是由IO工具的socket方法获得的,它的常用方法分别说明如下:
    ● connect:建立Socket连接。
    ● connected:判断是否连上Socket。
    ● emit:向服务器提交指定事件的消息。
    ● on:开始监听服务端推送的事件消息。
    ● off:取消监听服务端推送的事件消息。
    ● disconnect:断开Socket连接。
    ● close:关闭Socket连接。
    关闭之后要重新获取新的Socket对象才能连接。
    在两部手机之间Socket通信依旧区分发送方与接收方,且二者的消息收发通过Socket服务器中转。
    对于发送方的App来说,发消息的Socket操作流程为:获取Socket对象→调用connect方法→调用emit方法往Socket服务器发送消息。
    对于接收方的App来说,收消息的Socket操作流程为:获取Socket对象→调用connect方法→调用on方法从服务器接收消息。
    若想把Socket消息的收发功能集中在一个App,让它既充当发送方又充当接收方,则整理后的App消息收发流程如图【双向Socket通信的App消息收发流程】所示。

    双向Socket通信的App消息收发流程.png
    在上图【双向Socket通信的App消息收发流程】中的实线表示代码的调用顺序,虚线表示异步的事件触发,例如用户的点击事件以及服务器的消息推送等。根据这个收发流程编写代码逻辑,具体的实现代码如下:SocketioTextActivity
    public class SocketIoTextActivity extends AppCompatActivity {
        private static final String TAG = "SocketioTextActivity";
        private EditText et_input; // 声明一个编辑框对象
        private TextView tv_response; // 声明一个文本视图对象
        private Socket mSocket; // 声明一个套接字对象
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_socketio_text);
            et_input = findViewById(R.id.et_input);
            tv_response = findViewById(R.id.tv_response);
            findViewById(R.id.btn_send).setOnClickListener(v -> {
                String content = et_input.getText().toString();
                if (TextUtils.isEmpty(content)) {
                    Toast.makeText(this, "请输入聊天消息", Toast.LENGTH_SHORT).show();
                    return;
                }
                mSocket.emit("send_text", content); // 往Socket服务器发送文本消息
            });
            initSocket(); // 初始化套接字
        }
    
        // 初始化套接字
        private void initSocket() {
            // 检查能否连上Socket服务器
            SocketUtil.checkSocketAvailable(this, NetConst.BASE_IP, NetConst.BASE_PORT);
            try {
                String uri = String.format("http://%s:%d/", NetConst.BASE_IP, NetConst.BASE_PORT);
                mSocket = IO.socket(uri); // 创建指定地址和端口的套接字实例
            } catch (URISyntaxException e) {
                throw new RuntimeException(e);
            }
            mSocket.connect(); // 建立Socket连接
            // 等待接收传来的文本消息
            mSocket.on("receive_text", (args) -> {
                String desc = String.format("%s 收到服务端消息:%s",
                        DateUtil.getNowTime(), (String) args[0]);
                runOnUiThread(() -> tv_response.setText(desc));
            });
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            mSocket.off("receive_text"); // 取消接收传来的文本消息
            if (mSocket.connected()) { // 已经连上Socket服务器
                mSocket.disconnect(); // 断开Socket连接
            }
            mSocket.close(); // 关闭Socket连接
        }
    }
    

    确保服务器的SocketServer正在运行服务端程序服务端使用说明,再运行并测试该App,在编辑框输入待发送的文本,此时交互界面如【交互界面】图所示。

    交互界面.png
    三、通过SocketIO传输图片消息

    相关文章

      网友评论

          本文标题:Android 即时通信

          本文链接:https://www.haomeiwen.com/subject/eyudddtx.html