java - android java套接字写入和接收byte[]数据

标签 java android sockets byte payload

我需要使用 Android 应用程序中的套接字将数据包发送到服务器。我只知道数据包布局:

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

有关 TLSv1.2 连接和自签名证书的所有内容都运行良好。例如,我需要发送身份验证数据包 - LoginRequest,如果数据包发送成功,服务器将使用 LoginResponse 进行响应。我想做的是连接到 AsyncTask 类中的服务器,写入数据并接收响应,但显然我做错了,因为我没有得到响应。写入和读取消息的代码:

LoginRequest protobuf 消息:

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

以及代码(在 doInBackground() 方法内):

//TLSSocketFactory is custom SSLSocketFactory class for forcing TLSv1.2 on devices > 16 & < 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);

但现在我遇到了 OOM 异常:

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 Alloc

然后抛出 OOM 异常。

最佳答案

问题出在 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);
}

感谢您的提示。

关于java - android java套接字写入和接收byte[]数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39889686/

相关文章:

java - 如何从文本文件中获取特定行?

java - 从 JSP 文件向 RequestParam 发送值时出现错误

android - 从数据库中检索数据时显示空指针异常

unix - 使用 fork 和 sockets 时处理不正常的关闭

Java Swing JComboBox Action 监听器

node.js - 带有React的Socket.io在出现5条消息后表现异常

Java ARP 扫描器

android - 识别在上下文菜单中选择的 View (Android)

android - 如何将对象从一个 fragment 传递到另一个 fragment ?

java - 调用远程 ESB 客户端错误