android java socket запись и получение байтовых [] данных

#java #android #sockets #byte #payload

#java #Android #сокеты #байт #полезная нагрузка

Вопрос:

Мне нужно отправить пакет на сервер с помощью сокета из моего приложения для Android. Я знаю только макет пакета:

 Packet ID 4 bytes | Packet length 4 bytes(minus len   ID) | payload (protobuf message)
  

Все, что касается подключения TLSv1.2 и самозаверяющего сертификата, работает хорошо. Например, мне нужно отправить пакет аутентификации — LoginRequest, и сервер ответит LoginResponse, если пакет был отправлен успешно. То, что я пытаюсь сделать, это подключиться к серверу внутри класса AsyncTask, записать данные и получить ответ, но, очевидно, я делаю это неправильно, потому что я не получил ответа. Код для записи и чтения сообщения:

Сообщение протобуфа LoginRequest:

 Protos.LoginRequest loginRequest = Protos.LoginRequest.newBuilder()
                    .setUsername(mailAddress)
                    .setPassword(pass).build();
  

И код (внутри метода doInBackground()):

 //TLSSocketFactory is custom SSLSocketFactory class for forcing TLSv1.2 on devices > 16 amp; < 20
socket = tlsSocketFactory.createSocket("airwave1.exurion.com", 2559);

byte[] payload = loginRequest.toByteArray();

DataOutputStream out = new DataOutputStream(socket.getOutputStream());
InputStream inStream = socket.getInputStream();

out.writeInt(10); //ID of the packet
out.writeInt(payload.length);
out.write(payload);

out.flush();

byte[] data = new byte[100];
int count = inStream.read(data);

out.close();
inStream.close();
socket.close();
  

Как я уже сказал, я не получил ответа, иногда я также получаю исключение SSLException при чтении сообщения:

 javax.net.ssl.SSLException: Read error: ssl=0xb3a28580: I/O error during system call, Connection timed out
  

У кого-нибудь есть идеи, как это решить?

// ОБНОВЛЕНО Я понял, что порядок байтов должен быть в LITTLE_ENDIAN, поэтому я попытался использовать ByteBuffer:

 //based on previous packet layout (4 bytes for ID, 4 bytes for payload length, and payload) - is it ByteBuffer.allocate() fine?
    ByteBuffer buffer = ByteBuffer.allocate(8   payload.length);
    buffer.order(ByteOrder.LITTLE_ENDIAN);

    buffer.putInt(LoginPacketType.LOGIN_REQUEST.getId());
    buffer.putInt(payload.length);
    buffer.put(payload);

    buffer.rewind();
    byte[] result = new byte[buffer.capacity()]; // Could also use result = buffer.array();
    buffer.get(result);

    out.write(result);
  

Но теперь я получаю исключение ООМ:

 Failed to allocate a 184549388 byte allocation with 16777216 free bytes and 155MB until OOM
  

Подробнее об этом:
После записи в DataOutputStream я делаю:

 buffer.clear()
out.flush();

//code for reading from InputStream
  

И теперь в моем журнале появляется это сообщение несколько раз:
Запуск блокирующего распределения GC

и затем выдает исключение ООМ.

Ответ №1:

Проблема была в порядке LITTLE_ENDIAN и BIG_ENDIAN. Серверы отправляют ответ в порядке LITTLE_ENDIAN, поэтому я немного переписываю ваш ответ:

 int type = inStream.readInt();
type = Integer.reverseBytes(type);
int length = inStream.readInt();
length = Integer.reverseBytes(length);

if (length > 0) {
    byte[] data = new byte[length];
    inStream.readFully(data);
    Protos.LoginResponse response = Protos.LoginResponse.parseFrom(data);
}
  

Спасибо за подсказку.

Ответ №2:

Вы пишете тип пакета, длину и полезную нагрузку, но вы только считываете полезную нагрузку. Вы также предполагаете, что read() это заполняет буфер.

 int type = din.readInt();
int length = din.readInt();
byte[] data = new byte[length];
din.readyFully(data);
  

Комментарии:

1. Спасибо за подсказку, но все еще не работает, он застрял при чтении. Вероятно, проблема заключается в отправке пакета, но я не могу в этом разобраться.

2. Если этот код застрял при чтении, другой конец не отправляет этот протокол.

3. Что din здесь должно быть?