Comunicación de Android Socket (1) -comunicación basada en el protocolo UDP

Recientemente, la función necesita usar el protocolo UDP para comunicarse con el servidor. No he tocado este antes, así que dediqué un tiempo a entenderlo e implementarlo. Déjame grabarlo y compartirlo aquí.

En primer lugar, debemos saber que el protocolo de comunicación UDP es una implementación de la comunicación Socket, que generalmente tiene dos métodos de comunicación: basado en el protocolo TCP y basado en el protocolo UDP . No se mencionarán las diferencias y ventajas y desventajas de ambos, aquí hablamos principalmente de la implementación basada en el protocolo UDP.

Fundamental

La comunicación basada en UDP se realiza a través de la clase java.net.DatagramSocket. Normalmente usamos los métodos connect (), disConnect (), send () y receive (). Podemos distinguir fácilmente el uso por el nombre del método. Otra cosa que hay que saber es la clase DatagramPacket. Si DatagramSocket se compara con una tubería, DatagramPacket es el elemento transportado en la tubería, es decir, es el portador de datos.

DatagramSocket:

public DatagramSocket()throws SocketException {
    this(0);
}

public DatagramSocket(int aPort)throws SocketException {
    checkPort(aPort);
    createSocket(aPort, Inet4Address.ANY);
}

public DatagramSocket(int aPort, InetAddress addr)throws SocketException {
    checkPort(aPort);
    createSocket(aPort, (addr == null) ? Inet4Address.ANY : addr);
}

Para los tres métodos de construcción, podemos especificar el puerto y la IP o no. Al enviar datos, especificar en el paquete de datos.

DatagramPacket:

public DatagramPacket(byte[]data, int length) {…}
public DatagramPacket(byte[]data, int offset, int length) {…}
public DatagramPacket(byte[]data, int offset, int length, InetAddress host, int aPort) {…}
public DatagramPacket(byte[]data, int length, InetAddress host, int port) {…}

para que podamos ver que la ip y el puerto se pueden configurar en el paquete de datos, por lo que está bien si no lo especifica al conectarse.

Operación básica

1. Connect new crea un objeto DatagramSocket, establece el puerto y la IP, y connect ();
2. send crea un objeto DatagramPacket, socket.send (paquete) envía datos;
3. Receive crea un objeto DatagramPacket, socket.receive (paquete) recibe datos;

Crea una conexión

Utilice el método de conexión para crear una conexión Socket

public void connect() {
    if (mSocket == null || mSocket.isClosed()) {
        try {
            //获取连接 ip:192.168.1.3  port:11069
            InetAddress address = InetAddress.getByName(Command.udp_address);
            mSocket = new DatagramSocket();
            mSocket.connect(address, Command.udp_port);
            messageQueue = new ArrayList < String > ();
            //开启接收线程
            mReceiveThread = new ReceiveThread();
            mReceiveThread.start();
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }
}

Envíe datos con regularidad para mantener la comunicación

Si desea mantener la comunicación, debe utilizar hilos. Si envía datos con regularidad, puede utilizar Handler o puede utilizar AlarmManager. Solo usa Handler aquí.

Cuando escribí, leí un montón de blogs. Al enviar, se usa un nuevo hilo para enviar datos. Después del envío, se escribe el código para recibir los datos, y no hay reciclaje o qué, solo se puede reciclar a través de GC. Por supuesto, generalmente no es Algo está mal, ¡pero en realidad hay grandes problemas! Debido a que mi proyecto requiere algunas operaciones correspondientes después de recibir la respuesta del servidor, entonces, debido a que cada hilo está esperando recibir datos, después de que el servidor responde con un dato, cada hilo aquí responde (Responda al servidor con un dato diferente), 10s crean un hilo para enviar datos, el servidor responderá después de un período de tiempo, ¡y luego explota instantáneamente!

Por lo tanto, la recepción y el envío deben estar separados y no pueden bloquearse en el mismo hilo. Al principio pensé en el principio y mecanismo de Handler. Quería imitarlo en un bucle sin fin para obtener datos de una cola. Si hay datos, envíelos. La idea es que se pueda enviar sin problemas, pero cuando quiero eliminarlo de la lista después de que el envío sea exitoso Después de los datos, no funcionará, el hilo está bloqueado. La razón específica debería ser el interbloqueo, porque la lista de datos está definida en el hilo principal, y luego ha sido ocupada por el hilo de trabajo, y el objeto no se puede obtener para la operación de eliminación. Después de esperar un cierto período de tiempo, se bloqueó directamente (mi análisis es este de).

Ok, luego escribe dos hilos, un SendThread, un ReceiveThread y el envío de tiempo de 10 segundos a través del control Handler.

Enviar hilo:

public class SendThread extends Thread {
    @ Override
    public void run() {
        super.run();
        try {
            if (mSocket == null || mSocket.isClosed())
                return;
            if (messageQueue.size() < 1)
                return;
            //发送
            final String data = messageQueue.get(0);
            byte[]datas = data.getBytes();
            InetAddress address = InetAddress.getByName(Command.udp_address);
            final DatagramPacket packet = new DatagramPacket(datas, datas.length, address, Command.udp_port);
            mSocket.send(packet);
            Logs.e("ConnectManager", "send success data is:" + data);
            messageQueue.remove(0);

        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Recibiendo hilo:

private class ReceiveThread extends Thread {
    @ Override
    public void run() {
        super.run();
        if (mSocket == null || mSocket.isClosed())
            return;
        try {
            byte datas[] = new byte[512];
            DatagramPacket packet = new DatagramPacket(datas, datas.length, address, Command.udp_port);
            mSocket.receive(packet);
            String receiveMsg = new String(packet.getData()).trim();
            Logs.e("ConnectManager", "receive msg data is:" + receiveMsg);
            mHandler.sendEmptyMessage(2);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Podemos ver que los datos solo se reciben una vez en ReceiveThread, entonces, ¿cómo mantener la comunicación? ¿Recibir mensajes? ¡Manipulador! Después de recibir el mensaje, enviamos un mensaje a través del Handler. ¿Qué hace este mensaje? Reinicie el hilo, lo que significa que continuará recibiendo datos. En este caso, se garantiza que solo un hilo está recibiendo datos.

private Handler mHandler = new Handler() {
    @ Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        if (msg.what == 2) {
            mReceiveThread.interrupt();
            mReceiveThread = null;
            mReceiveThread = new ReceiveThread();
            mReceiveThread.start();
        }
    }
};

Del mismo modo, Handler también realiza el envío de datos con regularidad. Envíe un mensaje cada 10 segundos, deje que el conector envíe un paquete de datos y envíese el mismo mensaje enviado 10 segundos después, de todos modos, usted se controla.

Enviar un mensaje:

public void sendPackageRegister() {
    String content = "(1001," + Command.deviceId + ",register)";
    messageQueue.add(content);
    mSendThread.interrupt();
    mSendThread = null;
    mSendThread = new SendThread();
    mSendThread.start();
}

Finalmente, recuerde detener el Handler y seguir enviando datos y detener el hilo.

¡Trabaja duro, ve más allá!

Sitio web personal: http://www.lizebin.info

github:https://github.com/lizebinbin

Supongo que te gusta

Origin blog.csdn.net/lizebin_bin/article/details/62423373
Recomendado
Clasificación