Почему я могу получать трансляции, но не общаться с конкретным сокетом в моем приложении? - PullRequest
0 голосов
/ 07 сентября 2018

Сначала немного информации о моей настройке. У меня есть мобильный телефон S8, где я запускаю это приложение на основе демонстрации AR-Devkit от Google.

  public void closeSocket(DatagramSocket socket) {

    if (socket != null && socket.isConnected() ) {
        while (!socket.isConnected()) {
            socket.disconnect();
            try {
                Thread.sleep(SpringAR.TIME_OUT_IN_BROADCAST);
            } catch (InterruptedException e) {
                Log.d(SpringAR.protocollDebugLogPrefix, " Socket Closing interrupted");
                e.printStackTrace();
            }
        }
    }

    if (socket != null && !socket.isClosed()) {
        socket.close();
        while (!socket.isClosed()) {
            try {
                Thread.sleep(SpringAR.TIME_OUT_IN_BROADCAST);
            } catch (InterruptedException e) {
                Log.d(SpringAR.protocollDebugLogPrefix, " Socket Closing interrupted");
                e.printStackTrace();
            }
        }
    }
}

public DatagramSocket createSocket(InetAddress ipAddress, int port) {
    try {
        DatagramSocket socket = new DatagramSocket(null);
        InetSocketAddress address = new InetSocketAddress(ipAddress, port);
        socket.setReuseAddress(true);
        socket.bind(address);

        return socket;

    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

public DatagramSocket getBroadcastListenerSocket() throws IOException {

    InetSocketAddress anyAdress = new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 9000);
    DatagramSocket socket = new DatagramSocket(null);
    socket.setSoTimeout(30);
    socket.setReuseAddress(true);
    socket.bind(anyAdress);
    return socket;
}

public DatagramSocket getBroadcastSenderSocket(DatagramSocket oldSocket) {

    DatagramSocket socket = null;
    try {
        ARDeviceAddress = InetAddress.getByName(comonUtils.getIPAddress(true));
        socket = getSocket(oldSocket, ARDeviceAddress, SpringAR.UDP_SERVER_PORT, null);
        socket.setBroadcast(true);
        socket.setSoTimeout(SpringAR.TIME_OF_FRAME_IN_MS);
    } catch (IOException e) {
        e.printStackTrace();
    }

    return socket;
}

public DatagramSocket getSocket(DatagramSocket oldSocket, InetAddress ipAddress, int port, InetAddress targetAddress) {

    if (oldSocket != null ) {
        closeSocket(oldSocket);
    }
    DatagramSocket socket = null;
    try {
        socket = createSocket(ipAddress, port);
        socket.setBroadcast(false);
        socket.setSoTimeout(SpringAR.TIME_OF_FRAME_IN_MS);
        if (targetAddress != null)
          socket.connect(targetAddress, port);

    } catch (SocketException e) {
        e.printStackTrace();
    }
    return socket;
}

 public class DatagramReciever extends Thread {

        private String datagramToSend = "";
        private boolean newDatagramToSend = false;
        private DatagramPacket snd_packet;

        DatagramSocket senderSocket = null;
        DatagramSocket listenerSocket = null;
        private DatagramSocket broadCastListenerSocket;

        //Buffer gettters and setters
        private int writeBuffer = 0;
        private SpringAR.comStates oldState;

        int getReadBuffer() {
            if (writeBuffer == 1) return 0;
            return 1;
        }

        void switchBuffer() {
            recieveByteIndex = 0;
            writeBuffer = getReadBuffer();
        }

        public String dbg_message = "";
        //Management Communication Headers

        public void kill() {
            closeSocket(senderSocket);
            closeSocket(listenerSocket);
            closeSocket(broadCastListenerSocket);
        }



        public void run() {

            try {

                initializeBroadcastConnection();

                while (true) {

                    //Recieving Datagramm
                    DatagramPacket rcv_packet = new DatagramPacket(rcv_message[writeBuffer], rcv_message[writeBuffer].length);
                    boolean NewMessageArrived = true;
                    try {
                        listenerSocket.receive(rcv_packet);
                    } catch (SocketTimeoutException e) {
                          NewMessageArrived = false;
                    }
                    //Watchdog
                    handleWatchDogTimer(State);

                    //TODO Delete String conversion
                    if (NewMessageArrived) {
                        dbg_message = new String(rcv_message[writeBuffer], 0, rcv_packet.getLength(), "US-ASCII");
                        Log.d(SpringAR.dataDebugLogPrefix, "" + rcv_packet.getAddress().getHostAddress() + ": " + dbg_message.trim() + " of " + rcv_packet.getLength() + "length ");
                    }

                    if (validatePackageSender(rcv_packet)) {
                        connectionStateMachine(rcv_message, rcv_packet);
                    }

                    //Sending Datagram
                    if (newDatagramToSend && hostIpAddress != null) {
                        //Log.d(SpringAR.protocollDebugLogPrefix, "Server sending: " + datagramToSend);
                        byte[] snd_message = datagramToSend.getBytes();

                        try {
                            snd_packet = packSendPackageByState(snd_message);
                            assert (snd_packet != null);
                            senderSocket.send(snd_packet);
                            newDatagramToSend = false;
                        } catch (IOException e1) {
                            e1.printStackTrace();
                            //causes     Caused by: android.system.ErrnoException: sendto failed: EINVAL (Invalid argument)
                            Log.e(SpringAR.protocollDebugLogPrefix, "Server Error in State: " + State.name());
                           break;
                        }

                    }

                }
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }

        private void initializeBroadcastConnection() throws IOException {
            ARDeviceAddress = InetAddress.getByName(comonUtils.getIPAddress(true));
            senderSocket = getSocket(null, ARDeviceAddress, SpringAR.UDP_SERVER_PORT, null);
            broadCastListenerSocket = getBroadcastListenerSocket();
            listenerSocket = broadCastListenerSocket;
            Log.d(SpringAR.protocollDebugLogPrefix, "initializeBroadcastConnection completed");
        }


        // handles management traffic like configurstion files
        private void connectionStateMachine(byte[][] payload, DatagramPacket rcv_packet) throws IOException {
            //Reset triggered by Host
            if (comonUtils.indexOf(payload[writeBuffer], SpringAR.recieveResetHeaderByte) != SpringAR.STRING_NOT_FOUND) {
                State = SpringAR.comStates.STATE_resetCommunication;
            }

            Log.d(SpringAR.protocollDebugLogPrefix, "ConnectionStateMachine: " + State.name());
            switch (State) {
                case STATE_resetCommunication: {
                    messageCounter = 0;
                    listenerSocket = broadCastListenerSocket;
                    hostIpAddress = comonUtils.getBroadcastAddress(context);
                    senderSocket = getBroadcastSenderSocket(senderSocket);
                    setSendToSpringMessage(SpringAR.sendResetHeader);
                    State = SpringAR.comStates.STATE_broadCastHeader;

                    return;
                }

                case STATE_broadCastHeader: {
                    if (comonUtils.indexOf(payload[writeBuffer], SpringAR.recieveHostReplyHeaderByte) != SpringAR.STRING_NOT_FOUND) {
                        Log.d(SpringAR.protocollDebugLogPrefix, " Host Reply Header recieved");
                        //Extract the hostIp
                        String hostIpAdressAsString = new String(payload[writeBuffer]);
                        hostIpAdressAsString = hostIpAdressAsString.replace(SpringAR.recieveHostReplyHeader, "").trim();
                        Log.d(SpringAR.dataDebugLogPrefix, hostIpAdressAsString);

                        hostIpAddress = InetAddress.getByName(hostIpAdressAsString);

                        //Set Connection from broadcast to target
                        ARDeviceAddress = InetAddress.getByName(comonUtils.getIPAddress(true));
                        Log.d(SpringAR.protocollDebugLogPrefix, " New Device Adress " + ARDeviceAddress);
                        senderSocket = getSocket(senderSocket, ARDeviceAddress, SpringAR.UDP_SERVER_PORT, hostIpAddress);
                        listenerSocket = senderSocket;
                        State = SpringAR.comStates.STATE_sendCFG;
                        return;
                    }


                    setSendToSpringMessage(SpringAR.sendBroadcasteHeader);

                    delayByMs(SpringAR.TIME_OUT_IN_BROADCAST);
                    return;
                }

                case STATE_sendCFG: {
                    if ( SpringAR.STRING_NOT_FOUND != comonUtils.indexOf(payload[writeBuffer], SpringAR.recieveCFGHeaderByte )) {

                        State = SpringAR.comStates.STATE_sendRecieveData;
                        return;
                    }

                    setSendToSpringMessage(SpringAR.formConfigurationMessage());
                    return;
                }

                case STATE_sendRecieveData: {
                    if ( SpringAR.STRING_NOT_FOUND != comonUtils.indexOf(payload[writeBuffer], SpringAR.recieveDataHeaderByte)) {
                        writeRecievedDataToBuffer(payload[writeBuffer], rcv_packet.getLength());
                    }
                    break;
                }
                default:
                    Log.d(SpringAR.protocollDebugLogPrefix, "Connection State Machine invalid state");

            }


}

https://github.com/PicassoCT/arcore-android-sdk/blob/6c9b48a3d520e039cd48bc2af7354ccdec857736/arcore-android-sdk/samples/hello_ar/app/src/main/java/com/google/ar/core/examples/app/common/tcpClient/Server.java

Все тестирование происходит в домашней настройке WiFi, где рабочий стол с хост-приложением напрямую подключен к WiFi-маршрутизатору.

Что работает до сих пор: Устройство может транслировать свое присутствие. Хост может транслировать свою конфигурацию. Устройство не может общаться с IP на IP на хосте. Обе стороны имеют фиксированный набор IP.

Я могу связаться с App PacketSender с хост-приложением и исключить ошибку с его стороны.

Я также создал меньшую отладочную петлю, чтобы отправлять только пакеты udp туда и обратно, что также работало.

Спасибо за ваше время

Captured Packages-Showing Broadcast going from the ARDevice to the Host-Application and a direktional Answer by the HostApplication, that is never recieved on the ARDevice

1 Ответ

0 голосов
/ 09 сентября 2018

Изменить эту строку:

socket.setSoTimeout(30);

до

socket.setSoTimeout(1000);

У вас здесь довольно сложный конечный автомат, и трудно увидеть, что происходит, без просмотра журналов. Я бы обобщил ваш конечный автомат так:

  1. Трансляция сообщения о конфигурации
  2. Потратьте 30 мс на прослушивание ответа
  3. Если ответ не получен, заблокируйте для SpringAR.TIME_OF_FRAME_IN_MS (не входит в ваш код; я предполагаю, что это 1000 мс) и вернитесь к # 1
  4. Если ответ получен, отправьте ответ непосредственно партнеру и перейдите к # 2

# 4 - это шаг, который не происходит. Вероятная причина (на основе дампа Wireshark) заключается в том, что для ответа ARDevice на «Host» требуется 68 мс. Вы дали только 30 мс. Может быть несколько причин, по которым это занимает так много времени, но это выходит за рамки вашего вопроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...