android java 套接字写入和接收byte[]数据
android java socket write and receive byte[] data
我需要使用 android 应用程序中的套接字将数据包发送到服务器。我只知道一个数据包布局:
Packet ID 4 bytes | Packet length 4 bytes(minus len + ID) | payload (protobuf message)
关于 TLSv1.2 连接和自签名证书的全部内容运行良好。例如,我需要发送身份验证数据包 - 如果数据包发送成功,LoginRequest 和服务器将响应 LoginResponse。我想做的是连接到 AsyncTask class 内的服务器,写入数据并接收响应,但显然我做错了,因为我没有得到响应。写入和读取消息的代码:
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 异常。
您正在编写数据包类型、长度和有效载荷,但您只是在读取有效载荷。您还假设 read()
填满了缓冲区。
int type = din.readInt();
int length = din.readInt();
byte[] data = new byte[length];
din.readyFully(data);
问题出在 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);
}
感谢提示。
我需要使用 android 应用程序中的套接字将数据包发送到服务器。我只知道一个数据包布局:
Packet ID 4 bytes | Packet length 4 bytes(minus len + ID) | payload (protobuf message)
关于 TLSv1.2 连接和自签名证书的全部内容运行良好。例如,我需要发送身份验证数据包 - 如果数据包发送成功,LoginRequest 和服务器将响应 LoginResponse。我想做的是连接到 AsyncTask class 内的服务器,写入数据并接收响应,但显然我做错了,因为我没有得到响应。写入和读取消息的代码:
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 异常。
您正在编写数据包类型、长度和有效载荷,但您只是在读取有效载荷。您还假设 read()
填满了缓冲区。
int type = din.readInt();
int length = din.readInt();
byte[] data = new byte[length];
din.readyFully(data);
问题出在 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);
}
感谢提示。