android socket-udp通信

前言

  • UDP是无连接协议,即是在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来讲,当一台计算机向另一台计算机发送数据时,发送端不会决定接收方存不存在,就会发出数据,同样接受端在收到数据时,也不会向发送端反馈是否接到数据。
  • 本文基于同一局域网下设备交互场景讲解。
  • udp本身没有c/s的概念,为了方便区分为客户端和服务端。
  • 在android中发送和接收消息都需要在子线程中操作。

发送消息

  • 为了保证消息发送成功,规定了服务端接收到消息必须给返回响应数据
  • TIMEOUT设置发送消息后等待响应的时间,RETRY_NUM设置重发的次数。
    /**
     * 发送udp消息
     *
     * @param ip       ip地址
     * @param port     端口
     * @param data     数据
     * @param callback 响应数据回调
     */
    public static void sendMessage(String ip, int port, String data, UDPCallback callback) {
        mPool.execute(() -> {
            try {
                InetAddress inetAddress = InetAddress.getByName(ip);
                DatagramSocket client = new DatagramSocket();
                // 设置接收数据时阻塞的最长时间
                client.setSoTimeout(TIMEOUT);
                // 发送数据包
                byte[] dataBytes = data.getBytes();
                DatagramPacket dataPacket = new DatagramPacket(dataBytes, dataBytes.length, inetAddress, port);
                // 响应数据包
                byte[] responseBytes = new byte[1024 * 1024];
                DatagramPacket responsePacket = new DatagramPacket(responseBytes, responseBytes.length);
                int tries = 0;
                boolean receivedResponse = false;
                while (!receivedResponse && tries < RETRY_NUM) {
                    // 发送数据
                    client.send(dataPacket);
                    try {
                        // 响应数据
                        client.receive(responsePacket);
                        String serviceIp = responsePacket.getAddress().getHostAddress();
                        String response = new String(responseBytes, 0, responsePacket.getLength());
                        if (callback != null) {
                            ThreadUtils.runOnUiThread(() -> callback.call(serviceIp, response));
                        }
                        receivedResponse = true;
                    } catch (InterruptedIOException e) {
                        // 如果接收数据时阻塞超时,重发并减少一次重发的次数
                        tries += 1;
                        Log.e("udp", "client Time out," + (RETRY_NUM - tries) + " more tries...");
                    }
                }
                Log.e("udp", "client No response -- give up.");
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

接收消息

  • 接收消息receive方法是阻塞的,控制死循环一直接收消息
    /**
     * 接收udp消息
     *
     * @param port     端口
     * @param repeat   重复接收
     * @param response 响应数据
     * @param callback 接收数据回调
     */

    public static void receiveMessage(int port, boolean repeat, String response, UDPCallback callback) {
        isReceiveRunning = true;
        mPool.execute(() -> {
            try {
                // 接收数据
                byte[] dataBytes = new byte[1024 * 1024];
                final DatagramPacket clientPacket = new DatagramPacket(dataBytes, dataBytes.length);
                DatagramSocket service = new DatagramSocket(null);
                service.setReuseAddress(true);
                service.bind(new InetSocketAddress(port));
                do {
                    service.receive(clientPacket);
                    String clientIp = clientPacket.getAddress().getHostAddress();
                    String data = new String(dataBytes, 0, clientPacket.getLength());
                    ThreadUtils.runOnUiThread(() -> callback.call(clientIp, data));
                    // 响应数据
                    byte[] responseBytes = (response == null ? "default response" : response).getBytes();
                    DatagramPacket responsePacket = new DatagramPacket(responseBytes, responseBytes.length, clientPacket.getAddress(), clientPacket.getPort());
                    service.send(responsePacket);

                } while (repeat && isReceiveRunning);

                service.disconnect();
                service.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        });

    }

建立连接

  • 建立连接逻辑是客户端和服务端绑定不同的端口,客户端发送广播到指定的服务端端口,服务端接收广播发送的消息并响应,双方获取到对应的IP以实现一对一的发送。
    /**
     * 重复发送udp广播
     *
     * @param port     端口
     * @param data     数据
     * @param interval 间隔时间
     * @param callback 响应回调
     */
    public static void sendBroadcast(int port, String data, int interval, UDPCallback callback) {
        isSendBroadcastRunning = true;
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                sendMessage(NetworkUtils.getBroadcastIpAddress(), port, data, callback);
                if (isSendBroadcastRunning) {
                    mHandler.postDelayed(this, interval);
                }
            }
        };
        mHandler.postDelayed(runnable, interval);
    }

    /**
     * 发送udp广播
     *
     * @param port     端口
     * @param data     数据
     * @param callback 响应回调
     */
    public static void sendBroadcast(int port, String data, UDPCallback callback) {
        sendMessage(NetworkUtils.getBroadcastIpAddress(), port, data, callback);
    }
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值