从客户端套接字读取数据似乎缺少字节(从 java 到 python)
Read data from a client socket seems miss bytes (from java to python)
背景
我最近刚开始学习网络和 google 的协议缓冲区,以在我的 java 客户端与 python 服务器之间建立通信。从我的 python 服务器向 java 客户端发送消息完美无缺,但相反的方式(从 java 到 python)总是失败。
问题
在检查双方的消息长度后,我发现接收方(python)丢失了一些由java代码传输的字节,
java side:
12 28 08 0b 12 24 15 00 00 80 3f 1a 1b 09 00 00 00 00 00 00 f0 3f 11 00 00 00 00 00 00 f0 3f 19 00 00 00 00 00 00 f0 3f 22 00
python side:
12 28 08 0b 12 24 15 00 00 80 3f 1a 1b 09 00 00 00 00 00 00 f0 3f 11 00 00 00 00 00 00 f0 3f
如您所见,缺少最后 10 个字节。我无法弄清楚问题所在。
代码
以下是我的java代码,
// Both Message and UPDATEs are message types I defined in my .proto file
Message message = Message.newBuilder()
.setUpdate(UPDATEs.newBuilder()
.setTimeStamp(11)
.addUpdates(state))
.build();
//System.out.println(message.toString());
System.out.println(message.toByteArray().length); // result -> 42
//System.out.println(byteArrayToHex(message.toByteArray()));
try {
OutputStream outputStream = socket.getOutputStream();
message.writeDelimitedTo(outputStream);
System.out.println("Sending finished.");
} catch (IOException e) {
System.err.println("SteerCommunicator_sendCarData(OutputStream output): " + e.toString());
System.exit(0);
}
和我的 python 代码,
def server_loop():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "Listening at port {}".format(PORT)
try:
server.bind(("localhost", PORT))
except:
print "Unable to listen on the Port" + PORT
sys.exit()
server.listen(10)
while True:
client_socket, addr = server.accept()
print "Received Message from Client {}:{}".format(addr[0],str(addr[1]))
msg = client_socket.recv(1024)
print len(msg) # result -> 32
有什么想法吗?
如果流没有被刷新的诊断是正确的,那么这里是解决方案:
try (OutputStream outputStream = socket.getOutputStream()) {
message.writeDelimitedTo(outputStream);
System.out.println("Sending finished.");
} catch (IOException e) {
// SEE NOTES!!
System.err.println("blah blah" + e.toString());
System.exit(0);
}
说明:通过使用try-with-resources,我们确保资源总是在块退出时关闭,无论如何 它退出。这有两个好处:
- 它确保流被刷新
- 它确保您不会泄漏资源(即关联的
FileDescriptor
)。资源泄漏可能导致各种不相关的 I/O activity 失败......稍后......如果 GC 没有机会先清理混乱。
备注:
在代码深处调用 System.exit(...)
是个坏主意。它抢占了其他可能的恢复方法,并使您的代码更难扩展 and/or 重用。
如果您捕获并报告异常,您还应该报告堆栈跟踪...某处。
更好的策略是声明 IOException
由封闭方法抛出,并在更高级别捕获/报告/恢复。
背景
我最近刚开始学习网络和 google 的协议缓冲区,以在我的 java 客户端与 python 服务器之间建立通信。从我的 python 服务器向 java 客户端发送消息完美无缺,但相反的方式(从 java 到 python)总是失败。
问题
在检查双方的消息长度后,我发现接收方(python)丢失了一些由java代码传输的字节,
java side:
12 28 08 0b 12 24 15 00 00 80 3f 1a 1b 09 00 00 00 00 00 00 f0 3f 11 00 00 00 00 00 00 f0 3f 19 00 00 00 00 00 00 f0 3f 22 00
python side:
12 28 08 0b 12 24 15 00 00 80 3f 1a 1b 09 00 00 00 00 00 00 f0 3f 11 00 00 00 00 00 00 f0 3f
如您所见,缺少最后 10 个字节。我无法弄清楚问题所在。
代码
以下是我的java代码,
// Both Message and UPDATEs are message types I defined in my .proto file
Message message = Message.newBuilder()
.setUpdate(UPDATEs.newBuilder()
.setTimeStamp(11)
.addUpdates(state))
.build();
//System.out.println(message.toString());
System.out.println(message.toByteArray().length); // result -> 42
//System.out.println(byteArrayToHex(message.toByteArray()));
try {
OutputStream outputStream = socket.getOutputStream();
message.writeDelimitedTo(outputStream);
System.out.println("Sending finished.");
} catch (IOException e) {
System.err.println("SteerCommunicator_sendCarData(OutputStream output): " + e.toString());
System.exit(0);
}
和我的 python 代码,
def server_loop():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "Listening at port {}".format(PORT)
try:
server.bind(("localhost", PORT))
except:
print "Unable to listen on the Port" + PORT
sys.exit()
server.listen(10)
while True:
client_socket, addr = server.accept()
print "Received Message from Client {}:{}".format(addr[0],str(addr[1]))
msg = client_socket.recv(1024)
print len(msg) # result -> 32
有什么想法吗?
如果流没有被刷新的诊断是正确的,那么这里是解决方案:
try (OutputStream outputStream = socket.getOutputStream()) {
message.writeDelimitedTo(outputStream);
System.out.println("Sending finished.");
} catch (IOException e) {
// SEE NOTES!!
System.err.println("blah blah" + e.toString());
System.exit(0);
}
说明:通过使用try-with-resources,我们确保资源总是在块退出时关闭,无论如何 它退出。这有两个好处:
- 它确保流被刷新
- 它确保您不会泄漏资源(即关联的
FileDescriptor
)。资源泄漏可能导致各种不相关的 I/O activity 失败......稍后......如果 GC 没有机会先清理混乱。
备注:
在代码深处调用
System.exit(...)
是个坏主意。它抢占了其他可能的恢复方法,并使您的代码更难扩展 and/or 重用。如果您捕获并报告异常,您还应该报告堆栈跟踪...某处。
更好的策略是声明
IOException
由封闭方法抛出,并在更高级别捕获/报告/恢复。