Программирование сокетов Android ... что дает? - PullRequest
3 голосов
/ 10 июля 2011

Итак, я покопался в сети (в основном это так, Google), чтобы найти хорошие примеры программирования сокетов под Android.Я сделал много Android разработчика (только не с сокетами).Я не понимаю, почему мой readLine () ВСЕГДА ВОЗВРАЩАЕТСЯ НУЛЬ.И, пожалуйста, не обращайте внимания на отвратительный код, это быстрый и грязный прототип для друга.Моя общая цель - установить соединение с сервером, отправить данные заголовка (GET / MOUNTPOINT Content-Type: ... и т.д ...) и получить ответ, основанный на ответе, который мне нужен, чтобы продолжить поток или закрытьЭто.Вот мой код последней попытки:

                    String userPass = new     String(Base64.encodeToString("user:password".getBytes(),     Base64.DEFAULT));
            boolean connected = false;
            String requestmsg = "GET /MOUNTPOINT" + " HTTP/1.0\r\n";
            requestmsg += "User-Agent: MYCUSTOMAGENT\r\n";
            requestmsg += "Accept: */*\r\n";
            requestmsg += "Connection: close\r\n";

            requestmsg += "Authorization: Basic " + userPass;

            requestmsg += "\r\n";
            DataOutputStream dos =  null;
            DataInputStream dis = null;
            try {

                Log.d("ClientActivity", "Connecting...");
                Socket socket = new Socket("1.2.3.4", 9000);
                connected = true;
                String data = "";

                while (connected) {
                    try {
                        Log.d("ClientActivity", "C: Sending command.");

                        dos = new DataOutputStream(socket.getOutputStream());
                        dis = new DataInputStream(socket.getInputStream());

                        dos.write(requestmsg.getBytes());
                        Log.i("ClientActivity", "RequestMsg Sent");

                        StringBuilder sb = new StringBuilder();

                        while ((data = dis.readLine()) != null)
                            {
                                sb.append(data);
                            }
                            Log.i("ClientActivity", "C: Sent.");
                    } catch (Exception e) {
                        Log.e("ClientActivity", "S: Error", e);

                    }
                }
                socket.close();
                Log.d("ClientActivity", "C: Closed.");
            } catch (Exception e) {
                Log.e("ClientActivity", "C: Error", e);
                connected = false;
            }

Я пытался использовать HttpClient API, но он вставляет сообщение «GET /» в заголовок, и мне нужно указать «GET / MOUNTPOINT».Плюс я не знаю, позволяет ли HttpClient потоковую передачу.Я также пробовал URLConnection, но он также вставляет GET или POST по умолчанию.Спасибо за любую помощь!

Также я попробовал следующее:

SocketAddress sockaddr = new InetSocketAddress("1.2.3.4", 9000);
nsocket = new Socket();

nsocket.connect(sockaddr, 10 * 1000); // 10 second connection timeout
    if (nsocket.isConnected()) {
        //nsocket.setSoTimeout(20 * 1000); // 20 second timeout once data is flowing
        nis = nsocket.getInputStream();
        nos = nsocket.getOutputStream();
        Log.i(NTAG, "Socket created, streams assigned");
        // Build request message
        requestmsg = "GET /MOUNTPOINT" + " HTTP/1.0\r\n";
        requestmsg += "User-Agent: MYANDROIDAGENT\r\n";
        requestmsg += "Accept: */*\r\n";
        requestmsg += "Connection: close\r\n";
        requestmsg += "Authorization: Basic " + userPass;
        requestmsg += "\r\n";

        nos.write(requestmsg.getBytes());


        nos.write(genGPGGA().getBytes());
        Log.i(NTAG, "Waiting for inital data...");
        byte[] buffer = new byte[4096];
        int read = nis.read(buffer); // This is blocking
        //Log.i("ReadNTRIP", tempdata.toString());
        String test = "TESTING";

        while (read != -1) {
            tempdata = new byte[read];
            System.arraycopy(buffer, 0, tempdata, 0, read);
            read = nis.read(buffer, 0, 4096); // This is blocking

        }
    }
} catch (SocketTimeoutException ex) {
    ex.printStackTrace();
} catch (Exception e) {
    e.printStackTrace();
} finally {
    try {
        nis.close();
        nos.close();
        nsocket.close();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }
    Log.i(NTAG, "Finished");

}

Но чтение всегда возвращает -1.Я готов вырвать свои волосы.

РЕДАКТИРОВАТЬ: Я добавил награду (стоит очень мало) - у меня не так много представителей, чтобы дать, но эта проблема стала для меня ограничением показа.Чтобы получить награду, напишите простую андроид-программу для подключения к thor.lsu.edu, порт 9000, отправьте простую команду GET / HTTP / 1.0 и фактически верните данные (используя сокеты - не может быть с URLConnection или HttpClient).Разместите программу и снимок экрана с результатами.Я пробовал так много разных способов, я не знаю, что еще делать (используя InputStreams, BufferedInputStreams, InputStreamReaders и т. Д ...).Я даже использовал пример программы для Android (ЭТО РАБОТАЕТ), но я до сих пор не вернул данные в своей реализации.Я не знаю, проблема с синхронизацией или что.

Спасибо

Редактировать: я заметил, что даже не могу просмотреть http://thor.lsu.edu:9000 в браузере Android.Это дает проблему со связью данных.Есть идеи, почему этот порт может быть заблокирован?

Ответы [ 2 ]

9 голосов
/ 18 июля 2011

Все, что я сделал, - это несколько модификаций вашего кода. Я думаю, что основным изменением было просто не использование DataInputStream, поскольку в документации явно сказано, чтобы больше не использовать readLine () для этой структуры данных. http://download.oracle.com/javase/1.4.2/docs/api/java/io/DataInputStream.html#readLine%28%29

Я также удаляю материал авторизации, поскольку он не требуется. Если вы где-нибудь запустите этот код, вы заметите, что журнал распечатывает ответ HTTP.

String requestmsg = "GET /MOUNTPOINT" + " HTTP/1.0\r\n";
    requestmsg += "User-Agent: MYCUSTOMAGENT\r\n";
    requestmsg += "Accept: */*\r\n";
    requestmsg += "Connection: close\r\n";

    // requestmsg += "Authorization: Basic " + userPass;

    requestmsg += "\r\n";
    DataOutputStream dos = null;
    BufferedReader dis = null;
    try {

        Log.d("ClientActivity", "Connecting...");
        Socket socket = new Socket("thor.lsu.edu", 9000);
        String data = "";

        try {
            Log.d("ClientActivity", "C: Sending command.");

            dos = new DataOutputStream(socket.getOutputStream());
            dis = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            dos.write(requestmsg.getBytes());
            Log.i("ClientActivity", "RequestMsg Sent");

            StringBuilder sb = new StringBuilder();

            while ((data = dis.readLine()) != null) {
                sb.append(data);
            }
            Log.i("ClientActivity", "C: Sent.");
            Log.i("ClientActivity", "C: Received " + sb.toString());
        } catch (Exception e) {
            Log.e("ClientActivity", "S: Error", e);

        }

        socket.close();
        Log.d("ClientActivity", "C: Closed.");
    } catch (Exception e) {
        Log.e("ClientActivity", "C: Error", e);
    }
2 голосов
/ 10 июля 2011

Одд. Я бы действительно предложил просто использовать URLConnection с URL http://1.2.3.4:9000/MOUNTPOINT. Это должно делать то, что вы хотите. Возможно, нулевая строка чтения вызвана тем, что ваш http-запрос, созданный вручную, не понимается другой стороной.

HttpClient позволяет осуществлять потоковую передачу, вам просто нужно реализовать довольно существенный кусок кода для его обработки.

РЕДАКТИРОВАТЬ: Интересно. Я смотрю на это в wget (мой инструмент для перехода к HTTP) и вижу это:

C:\Documents and Settings\Olufemi Omojola>wget -O - http://130.39.148.171:9000/
--21:31:55--  http://130.39.148.171:9000/
           => `-'
Connecting to 130.39.148.171:9000... connected.
HTTP request sent, awaiting response... 200 No headers, assuming HTTP/0.9
Length: unspecified

    [<=>                                                                          ] 0             --.--K/s             S
OURCETABLE 200 OK
Server: NTRIP Trimble NTRIP Caster
Content-Type: text/plain
Content-Length: 631
Date: 10/Jul/2011:01:31:37 UTC

STR;CMRp_All;CMRp_All;CMR+;1(1),3(10),18(1),19(1);2;GPS;GULFnet;USA;30.84;268.81;1;1;Trimble GPSNet;None;B;N;0;;
STR;RTCM2_3All;RTCM2_3All;RTCM 2.3;1(1),3(10),18(1),19(1);2;GPS;GULFnet;USA;30.84;268.81;1;1;Trimble GPSNet;None;B;N;0;;

STR;GLNnorthLA;GLNnorthLA;RTCM 3;1004(1),1005/1007(5),PBS(10);2;GPS+GLONASS;GULFNet;USA;0;0;1;1;Trimble GPSNet;None;B;N;
0;;
STR;GLNnoLA_CMRp;GLNnoLA_CMRp;CMR+;1004(1),1005/1007(5),PBS(10);2;GPS+GLONASS;GULFNet;USA;0;0;1;1;Trimble GPSNet;None;B;
N;0;;
STR;GLNseLA_CMRp;GLNseLA_CMRp;CMR+;1004(1),1005/1007(5),PBS(10);2;GPS+GLONASS;GULFNet;USA;0;0;1;1;Trimble GPSNet;None;B;
N;0;;
ENDSOURCETABLE
    [ <=>                                                                         ] 768           --.--K/s

21:31:55 (30.13 MB/s) - `-' saved [768]

C:\Documents and Settings\Olufemi Omojola>wget -O - http://130.39.148.171:9000/CMRp_All --http-user=user --http-password
=pass
--21:31:31--  http://130.39.148.171:9000/CMRp_All
           => `-'
Connecting to 130.39.148.171:9000... connected.
HTTP request sent, awaiting response... 401 Unauthorized
Authorization failed.

Отсутствие заголовков ответа может быть причиной сбоя URLConnection. Если вы продолжаете получать несанкционированные ответы, отправляемый вами заголовок авторизации может быть неправильным: для базовой аутентификации я делаю это.

httpost.addHeader("Authorization", "Basic " + Base64.encode(user+":"+pass).trim());

Это класс Base64, который я использую:

public class Base64 {
        private static final String base64code = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "+/";

        private static final int splitLinesAt = 76;

        public static byte[] zeroPad(int length, byte[] bytes) {
                byte[] padded = new byte[length]; // initialized to zero by JVM
                System.arraycopy(bytes, 0, padded, 0, bytes.length);
                return padded;
        }

        public static String encode(String string) {

                String encoded = "";
                byte[] stringArray;
                try {
                        stringArray = string.getBytes("UTF-8");  // use appropriate encoding string!
                } catch (Exception ignored) {
                        stringArray = string.getBytes();  // use locale default rather than croak
                }
                // determine how many padding bytes to add to the output
                int paddingCount = (3 - (stringArray.length % 3)) % 3;
                // add any necessary padding to the input
                stringArray = zeroPad(stringArray.length + paddingCount, stringArray);
                // process 3 bytes at a time, churning out 4 output bytes
                // worry about CRLF insertions later
                for (int i = 0; i < stringArray.length; i += 3) {
                        int j = ((stringArray[i] & 0xff) << 16) +
                        ((stringArray[i + 1] & 0xff) << 8) +
                        (stringArray[i + 2] & 0xff);
                        encoded = encoded + base64code.charAt((j >> 18) & 0x3f) +
                        base64code.charAt((j >> 12) & 0x3f) +
                        base64code.charAt((j >> 6) & 0x3f) +
                        base64code.charAt(j & 0x3f);
                }
                // replace encoded padding nulls with "="
                return splitLines(encoded.substring(0, encoded.length() -
                                paddingCount) + "==".substring(0, paddingCount));

        }
        public static String splitLines(String string) {

                String lines = "";
                for (int i = 0; i < string.length(); i += splitLinesAt) {

                        lines += string.substring(i, Math.min(string.length(), i + splitLinesAt));
                        lines += "\r\n";

                }
                return lines;

        }
}
...