|  |  | 
 |  |  | package com.hdl.sdk.socket.client;
 | 
 |  |  | 
 | 
 |  |  | 
 | 
 |  |  | import android.util.Log;
 | 
 |  |  | import android.text.TextUtils;
 | 
 |  |  | 
 | 
 |  |  | import com.hdl.sdk.common.HDLSdk;
 | 
 |  |  | import com.hdl.sdk.common.utils.IpUtils;
 | 
 |  |  | import com.hdl.sdk.common.utils.LogUtils;
 | 
 |  |  | import com.hdl.sdk.common.utils.ThreadToolUtils;
 | 
 |  |  | import com.hdl.sdk.socket.SocketBoot;
 | 
 |  |  | import com.hdl.sdk.socket.SocketOptions;
 | 
 |  |  | import com.hdl.sdk.socket.SocketPool;
 | 
 |  |  | import com.hdl.sdk.socket.annotation.ConnectStatus;
 | 
 |  |  | import com.hdl.sdk.socket.udp.UdpSocketBoot;
 | 
 |  |  | import com.hdl.sdk.socket.udp.UdpSocketOptions;
 | 
 |  |  | import com.hdl.sdk.socket.codec.IHandleMessage;
 | 
 |  |  | import com.hdl.sdk.socket.listener.ConnectStatusListener;
 | 
 |  |  | 
 | 
 |  |  | import java.io.IOException;
 | 
 |  |  | import java.net.DatagramPacket;
 | 
 |  |  | import java.net.DatagramSocket;
 | 
 |  |  | import java.net.InetAddress;
 | 
 |  |  | import java.net.InetSocketAddress;
 | 
 |  |  | import java.util.List;
 | 
 |  |  | import java.net.SocketAddress;
 | 
 |  |  | import java.util.concurrent.atomic.AtomicBoolean;
 | 
 |  |  | 
 | 
 |  |  | 
 | 
 |  |  | /**
 | 
 |  |  |  * Created by Tong on 2021/9/15.
 | 
 |  |  |  * 组播需要android.permission.CHANGE_WIFI_MULTICAST_STATE权限
 | 
 |  |  |  * MulticastSocket
 | 
 |  |  |  * Created by hxb on 2021/12/12.
 | 
 |  |  |  */
 | 
 |  |  | public class UdpClient implements IClient {
 | 
 |  |  | 
 | 
 |  |  |     private static DatagramSocket mSocket;
 | 
 |  |  | 
 | 
 |  |  |     private DatagramPacket receivePacket;
 | 
 |  |  | 
 | 
 |  |  |     private final int BUFFER = 4 * 1024;
 | 
 |  |  | 
 | 
 |  |  |     private final byte[] receiveByte;
 | 
 |  |  | 
 | 
 |  |  |     private final String ip;
 | 
 |  |  | 
 | 
 |  |  |     private final int port;
 | 
 |  |  | 
 | 
 |  |  |     private int monitorPort;
 | 
 |  |  |     private int sendPort;
 | 
 |  |  | 
 | 
 |  |  |     private SocketOptions socketOptions;
 | 
 |  |  | 
 | 
 |  |  |     private final AtomicBoolean isConnect = new AtomicBoolean(false);
 | 
 |  |  | public class UdpClient implements IUdpClient {
 | 
 |  |  | 
 | 
 |  |  |     /**
 | 
 |  |  |      * @param sendPort -1 表示随机端口
 | 
 |  |  |      * 当前socket
 | 
 |  |  |      */
 | 
 |  |  |     private UdpClient(String ip, int port, int monitorPort, int sendPort, SocketOptions socketOptions) {
 | 
 |  |  |     private  DatagramSocket mSocket;
 | 
 |  |  | 
 | 
 |  |  |     /**
 | 
 |  |  |      * 接收数据包
 | 
 |  |  |      */
 | 
 |  |  |     private DatagramPacket receivePacket;
 | 
 |  |  | 
 | 
 |  |  |     /**
 | 
 |  |  |      * 缓冲区大小
 | 
 |  |  |      */
 | 
 |  |  |     private final int BUFFER = 2 * 1024;
 | 
 |  |  | 
 | 
 |  |  |     /**
 | 
 |  |  |      * 本地监听IP地址
 | 
 |  |  |      */
 | 
 |  |  |     private String ipAddress;
 | 
 |  |  |     /**
 | 
 |  |  |      * 本地监听端口
 | 
 |  |  |      */
 | 
 |  |  |     private int port;
 | 
 |  |  | 
 | 
 |  |  |     /**
 | 
 |  |  |      * socket配置信息
 | 
 |  |  |      */
 | 
 |  |  |     private UdpSocketOptions socketOptions;
 | 
 |  |  | 
 | 
 |  |  |     /**
 | 
 |  |  |      * 初始化参数
 | 
 |  |  |      * @param ipAddress 本地监听端口
 | 
 |  |  |      * @param port 本地监听端口
 | 
 |  |  |      * @param socketOptions
 | 
 |  |  |      */
 | 
 |  |  |     private UdpClient(String ipAddress,int port, UdpSocketOptions socketOptions) {
 | 
 |  |  |         this.ipAddress = ipAddress;
 | 
 |  |  |         this.port = port;
 | 
 |  |  |         this.socketOptions = socketOptions;
 | 
 |  |  |         this.ip = ip;
 | 
 |  |  |         this.port = port;
 | 
 |  |  |         this.sendPort = sendPort;
 | 
 |  |  |         this.monitorPort = monitorPort;
 | 
 |  |  |         this.receiveByte = new byte[BUFFER];
 | 
 |  |  |         byte[] receiveByte = new byte[BUFFER];
 | 
 |  |  |         receivePacket = new DatagramPacket(receiveByte, receiveByte.length);
 | 
 |  |  |     }
 | 
 |  |  | 
 | 
 |  |  |     public UdpClient(String ip, int port) {
 | 
 |  |  |         this.ip = ip;
 | 
 |  |  |         this.port = port;
 | 
 |  |  |         this.receiveByte = new byte[BUFFER];
 | 
 |  |  |     /**
 | 
 |  |  |      * 初始化参数
 | 
 |  |  |      * @param ipAddress 本地监听IP地址
 | 
 |  |  |      * @param port 本地监听端口
 | 
 |  |  |      * @param options
 | 
 |  |  |      * @return
 | 
 |  |  |      */
 | 
 |  |  |     public static UdpSocketBoot init(String ipAddress, int port, UdpSocketOptions options) {
 | 
 |  |  |         return new UdpSocketBoot(new UdpClient(ipAddress, port, options));
 | 
 |  |  |     }
 | 
 |  |  | 
 | 
 |  |  |     public static SocketBoot init(String ip, int port, int monitorPort, int sendPort, SocketOptions options) {
 | 
 |  |  |         return new SocketBoot(new UdpClient(ip, port, monitorPort, sendPort, options));
 | 
 |  |  |     /**
 | 
 |  |  |      * 初始化参数
 | 
 |  |  |      * @param port 本地监听端口
 | 
 |  |  |      * @param options
 | 
 |  |  |      * @return
 | 
 |  |  |      */
 | 
 |  |  |     public static UdpSocketBoot init(int port, UdpSocketOptions options) {
 | 
 |  |  |         return init("0.0.0.0", port, options);
 | 
 |  |  |     }
 | 
 |  |  | 
 | 
 |  |  |     public static SocketBoot init(String ip, int port, int monitorPort, SocketOptions options) {
 | 
 |  |  |         return init(ip, port, monitorPort, -1, options);
 | 
 |  |  |     }
 | 
 |  |  | 
 | 
 |  |  |     public static SocketBoot init(String ip, int port, SocketOptions options) {
 | 
 |  |  |         return init(ip, port, port, -1, options);
 | 
 |  |  |     }
 | 
 |  |  | 
 | 
 |  |  |     @Override
 | 
 |  |  |     public void connect() throws Exception {
 | 
 |  |  |     public void bind() throws Exception {
 | 
 |  |  |         try {
 | 
 |  |  |             mSocket = SocketPool.getInstance().getUdpSocket(new InetSocketAddress(monitorPort));
 | 
 |  |  | 
 | 
 |  |  |             mSocket.setBroadcast(true);
 | 
 |  |  |             mSocket.setReuseAddress(true);
 | 
 |  |  |             isConnect.set(true);
 | 
 |  |  |             if (receivePacket == null) {
 | 
 |  |  |                 receivePacket = new DatagramPacket(receiveByte, BUFFER);
 | 
 |  |  |             //已经绑定过就不用再绑定
 | 
 |  |  |             if (null != mSocket) {
 | 
 |  |  |                 return;
 | 
 |  |  |             }
 | 
 |  |  |             if (TextUtils.isEmpty(ipAddress)) {
 | 
 |  |  |                 mSocket = SocketPool.getInstance().getUdpSocket(new InetSocketAddress(port));
 | 
 |  |  |             }else {
 | 
 |  |  |                 mSocket = SocketPool.getInstance().getUdpSocket(new InetSocketAddress(ipAddress,port));
 | 
 |  |  |             }
 | 
 |  |  |             mSocket.setBroadcast(true);
 | 
 |  |  | //            mSocket.setReuseAddress(true);
 | 
 |  |  | 
 | 
 |  |  |         } catch (Exception e) {
 | 
 |  |  |             isConnect.set(false);
 | 
 |  |  |             LogUtils.e("初始化Socket 失败:" + e.getMessage());
 | 
 |  |  |             throw e;
 | 
 |  |  |         }
 | 
 |  |  | 
 | 
 |  |  | 
 | 
 |  |  |     }
 | 
 |  |  | 
 | 
 |  |  |     @Override
 | 
 |  |  |     public void disconnect() {
 | 
 |  |  |         if (mSocket != null) {
 | 
 |  |  |     public boolean close() {
 | 
 |  |  |         try {
 | 
 |  |  |             mSocket.close();
 | 
 |  |  |         } catch (Exception e) {
 | 
 |  |  | 
 | 
 |  |  |         }
 | 
 |  |  |         isConnect.set(false);
 | 
 |  |  |         mSocket = null;
 | 
 |  |  |         return true;
 | 
 |  |  |     }
 | 
 |  |  | 
 | 
 |  |  |     @Override
 | 
 |  |  |     public boolean isConnect() {
 | 
 |  |  |         return isConnect.get();
 | 
 |  |  |     }
 | 
 |  |  | 
 | 
 |  |  |     @Override
 | 
 |  |  |     public synchronized SocketOptions getOptions() {
 | 
 |  |  |         if (socketOptions == null) {
 | 
 |  |  |             socketOptions = new SocketOptions();
 | 
 |  |  |         }
 | 
 |  |  |         return socketOptions;
 | 
 |  |  |     public UdpSocketOptions getOptions() {
 | 
 |  |  |         return this.socketOptions;
 | 
 |  |  |     }
 | 
 |  |  | 
 | 
 |  |  |     @Override
 | 
 |  |  |     public void onHandleResponse() throws Exception {
 | 
 |  |  |         if (receivePacket == null || mSocket == null) {
 | 
 |  |  |         if (mSocket == null) {
 | 
 |  |  |             return;
 | 
 |  |  |         }
 | 
 |  |  |         try {
 | 
 |  |  |             mSocket.receive(receivePacket);
 | 
 |  |  |         } catch (IOException e) {
 | 
 |  |  |             e.printStackTrace();
 | 
 |  |  |             isConnect.set(false);
 | 
 |  |  |         }
 | 
 |  |  |         if (receivePacket.getLength() == 0) {
 | 
 |  |  |             return;
 | 
 |  |  |         }
 | 
 |  |  |         //排除自己发出去的
 | 
 |  |  |         try {
 | 
 |  |  |             if (receivePacket.getAddress().getHostAddress()
 | 
 |  |  |                     .equals(IpUtils.getIP(HDLSdk.getInstance().getContext()))) {
 | 
 |  |  |             if (IpUtils.isLocalIpAddress(receivePacket.getAddress().getHostAddress()))
 | 
 |  |  |                 return;
 | 
 |  |  |             }
 | 
 |  |  |         } catch (Exception ignored) {
 | 
 |  |  | 
 | 
 |  |  |         }
 | 
 |  |  | 
 | 
 |  |  |         IHandleMessage handleMessage = getOptions().getHandleMessage();
 | 
 |  |  |         if (handleMessage != null) {
 | 
 |  |  |             handleMessage.read(receivePacket.getData());
 | 
 |  |  |         }
 | 
 |  |  |         final String receive = new String(receivePacket.getData(), 0, receivePacket.getLength());
 | 
 |  |  |         try {
 | 
 |  |  |             LogUtils.i("接收到Udp数据包,网络地址:" + receivePacket.getAddress().getHostAddress() + ":" + receivePacket.getPort());
 | 
 |  |  | 
 | 
 |  |  |         LogUtils.d("---->", receive + " from " + receivePacket.getAddress().getHostAddress() + ":" + receivePacket.getPort());
 | 
 |  |  | 
 | 
 |  |  |         //重置长度
 | 
 |  |  |         if (receivePacket != null) {
 | 
 |  |  |             receivePacket.setLength(BUFFER);
 | 
 |  |  |         }
 | 
 |  |  |     }
 | 
 |  |  | 
 | 
 |  |  |     @Override
 | 
 |  |  |     public void sendMsg(byte[] msg) throws Exception {
 | 
 |  |  |         if (msg == null) {
 | 
 |  |  |             msg = new byte[1];
 | 
 |  |  |         }
 | 
 |  |  |         InetAddress serverAddress = InetAddress.getByName(ip);
 | 
 |  |  |         final DatagramPacket sendPacket = new DatagramPacket(msg, msg.length, serverAddress, port);
 | 
 |  |  |         if (sendPort < 0) {
 | 
 |  |  |             final DatagramSocket sendSocket = new DatagramSocket();
 | 
 |  |  |             sendSocket.send(sendPacket);
 | 
 |  |  |             sendSocket.close();
 | 
 |  |  |         } else if (sendPort == monitorPort) {
 | 
 |  |  |             mSocket.send(sendPacket);
 | 
 |  |  |         } else {
 | 
 |  |  |             final DatagramSocket sendSocket = new DatagramSocket(sendPort);
 | 
 |  |  |             sendSocket.send(sendPacket);
 | 
 |  |  |             sendSocket.close();
 | 
 |  |  |         }
 | 
 |  |  | 
 | 
 |  |  |     }
 | 
 |  |  | 
 | 
 |  |  |     @Override
 | 
 |  |  |     public void onConnectStatus(int status) {
 | 
 |  |  |         ThreadToolUtils.getInstance().runOnUiThread(new Runnable() {
 | 
 |  |  |             @Override
 | 
 |  |  |             public void run() {
 | 
 |  |  |                 final List<ConnectStatusListener> list = getOptions().getConnectStatusListener();
 | 
 |  |  |                 if (list != null && !list.isEmpty()) {
 | 
 |  |  |                     for (ConnectStatusListener listener : list) {
 | 
 |  |  |                         switch (status) {
 | 
 |  |  |                             case ConnectStatus
 | 
 |  |  |                                     .CONNECTING:
 | 
 |  |  |                                 listener.onConnecting();
 | 
 |  |  |                                 break;
 | 
 |  |  |                             case ConnectStatus
 | 
 |  |  |                                     .CONNECTED:
 | 
 |  |  |                                 listener.onConnected();
 | 
 |  |  |                                 break;
 | 
 |  |  |                             case ConnectStatus
 | 
 |  |  |                                     .DISCONNECT:
 | 
 |  |  |                                 listener.onConnectFailed();
 | 
 |  |  |                                 break;
 | 
 |  |  |                         }
 | 
 |  |  |                     }
 | 
 |  |  |                 }
 | 
 |  |  |             IHandleMessage handleMessage = getOptions().getHandleMessage();
 | 
 |  |  |             if (handleMessage != null) {
 | 
 |  |  |                 byte[] data = new byte[receivePacket.getLength()];
 | 
 |  |  |                 System.arraycopy(receivePacket.getData(), 0, data, 0, data.length);
 | 
 |  |  |                 handleMessage.read(data,receivePacket.getAddress().getHostAddress());
 | 
 |  |  |             }
 | 
 |  |  |         });
 | 
 |  |  | 
 | 
 |  |  |         } catch (Exception e) {
 | 
 |  |  | 
 | 
 |  |  |         }
 | 
 |  |  |     }
 | 
 |  |  | 
 | 
 |  |  | 
 | 
 |  |  |     @Override
 | 
 |  |  |     public void sendMsg(String ipAddress,int port, byte[] msg) throws Exception {
 | 
 |  |  |         if (msg == null) {
 | 
 |  |  |             return;
 | 
 |  |  |         }
 | 
 |  |  |         final DatagramPacket sendPacket = new DatagramPacket(msg, msg.length, InetAddress.getByName(ipAddress), port);
 | 
 |  |  |         mSocket.send(sendPacket);
 | 
 |  |  |     }
 | 
 |  |  | }
 |