首页 \ 问答 \ Java NIO如何分解消息?(How does Java NIO break up messages?)

Java NIO如何分解消息?(How does Java NIO break up messages?)

我正在编写一个玩具Java NIO服务器与普通的Java客户端配对。 客户端使用普通Socket向服务器发送字符串消息。 服务器接收消息并将内容转储到终端。

我注意到来自客户端的相同消息每次都被分解为字节缓冲区。 我理解这是NIO的预期行为,但是想大致了解NIO如何决定切断消息?

示例:向服务器发送字符串“this is test message”。 以下是服务器日志记录的摘录(每行代表收到1个字节缓冲区)。

Run 1:
Server receiving: this is a test message

Run 2:
Server receiving: t
Server receiving: his is a test message

Run 3:
Server receiving: this is 
Server receiving: a test message

更新 - 问题已解决

我已经安装了Wireshark来分析数据包,很明显随机“分解”是因为我使用DataOutputStream作为DataOutputStream器,它逐字符地发送消息! 所以每个角色都有一个数据包......

BufferedWriter更改为BufferedWriter ,我的短消息现在按预期发送为单个数据包。 事实上,Java NIO实际上做了聪明的事情并将我的小数据包合并为1到2个字节的缓冲区!


UPDATE2 - 澄清

谢谢大家的回复。 感谢@StephenC指出,除非我自己编码消息(是的,我在写入BufferedWriter后调用了flush() ),总是有可能我的消息到达多个数据包。

所以事实是Java NIO实际上做了聪明的事情并且合并了我的小事

实际上,没有。 合并发生在BufferedWriter层中。 当应用程序刷新或关闭DataOutputStream或BufferdWriters缓冲区填满时,缓冲的写入器将仅向NIO层提供“一堆”字节。

我实际上指的是我第一次尝试使用DataOutputStream (我从网上的一个例子中得到了它,显然这是你已经指出它的不正确的类使用)。 BufferedWriter没有参与。 在那种情况下我的简单作家就像

DataOutputStream out = new DataOutputStream(socket.getOutputStream());
out.writeBytes("this is a test message");

Wireshark确认此消息已发送(localhost上的服务器)1个字符一个数据包(总共22个数据包用于实际消息,不包括所有ACK等)。

我可能错了,但这种行为似乎表明NIO服务器将这22个数据包组合成1-2个字节的缓冲区?


我试图在这里实现的最终游戏是一个简单的Java NIO服务器,它能够使用来自不同客户端的TCP接收请求和数据流,有些可能由第三方用C ++或C#编写。 这不是时间关键,因此客户端可以一次性发送所有数据,服务器可以按照自己的节奏处理它们。 这就是为什么我使用普通的Socket而不是NIO客户端用Java编写玩具客户端的原因。 因此,在这种情况下客户端不能直接操作ByteBuffer ,所以我可能需要某种消息格式。 我可以做这个吗?


I'm writing a toy Java NIO server paired with a normal Java client. The client sends a string message to the server using plain Socket. The server receives the message and dumps the content to terminal.

I've noticed that the same message from client is broken up into bytebuffers differently every single time. I understand this is intended behaviour of NIO, but would like to find out roughly how the NIO decides to chop up a message?

Example: Sending string "this is a test message" to server. The following are excerpts of server loggings (each line represents 1 bytebuffer received).

Run 1:
Server receiving: this is a test message

Run 2:
Server receiving: t
Server receiving: his is a test message

Run 3:
Server receiving: this is 
Server receiving: a test message

UPDATE - Issue Resolved

I have installed Wireshark to analyse the packets and it has become apparent that the random "break up" was due to me using DataOutputStream for the writer, which sends the message character by character! So there was a packet for each character...

After changing the writer to BufferedWriter, my short message is now sent as a single packet, as expected. So the truth is Java NIO actually did the clever thing and merged my tiny packets to 1 to 2 bytebuffers!


UPDATE2 - Clarification

Thank you all for your replies. Thank you @StephenC for pointing out that unless I encode the message myself(yes, I did call flush() after writing to BufferedWriter), there's always the possiblity of my message arriving across multiple packets.

So the truth is Java NIO actually did the clever thing and merged my tiny

Actually, no. The merging is happening in the BufferedWriter layer. The buffered writer will only deliver a "bunch" of bytes to the NIO layer when either the application flushes or closes the DataOutputStream or the BufferdWriters buffer fills up.

I was in fact referring to my first attempt with DataOutputStream (I got it from an example online, which obviously is incorrect use of the class now that you've pointed it out). BufferedWriter was not involved. My simple writer in that case went like

DataOutputStream out = new DataOutputStream(socket.getOutputStream());
out.writeBytes("this is a test message");

Wireshark confirmed that this message was sent(server on localhost) 1 character a packet(22 packets in total for the actual message not including all the ACK and etc).

I'm probably wrong, but this behaviour seems to suggest that the NIO server combined these 22 packets into 1-2 bytebuffers?


The end game I'm trying to achieve here is a simple Java NIO server capable of receiving request and data stream using TCP from various clients, some may be written in C++ or C# by third party. It's not time critical so the clients can send all data in one go and the server can process them at its own pace. That's why I've written a toy client in Java using plain Socket rather than a NIO client. Therefore the client in this case can't really manipulate the ByteBuffer directly, so I probably need some sort of message format. Could I make this work?


原文:https://stackoverflow.com/questions/42581185
更新时间:2023-10-25 20:10

最满意答案

它听起来像你不允许系统更新自己已经创建了一个新的媒体文件。 这就是你的方法失败的原因。 您可以手动创建映像文件路径,以便在文件树上具有映像位置,也可以调用媒体服务来运行更新。 我总是创建自己的文件路径,因为较旧的手机需要更长时间才能使用媒体服务进行更新,因此在这种情况下您的方法将失败。


Apparently this crash is due to a known Samsung problem: it seems like you need to create a Uri before calling the camera intent, in this way when running the onActivityResult method the content provider will allready have allocated the place where to save the resource.

For further information check the following:

and many more by googling...

P.S. as soon as possible I'll post the solution that worked for me.

相关问答

更多
  • 我不知道是什么导致了这个错误,如果你从发生这个错误的时间开始发布loggcat输出,这真的会有帮助。 但是,我可以制定一些措施。 它看起来像相机被锁定(内置相机不工作)。 如果您的应用程序部队关闭,相机锁可能是由三星相机HAL中错误的错误处理引起的。 尤其是在像Galaxy S这样的旧手机中,他们在处理错误的或不标准的API调用方面做得不是最好。 以下是可能导致此行为的一些建议: 你应该添加一个卫兵拍照。 现在,如果您触摸屏幕并拍摄照片,则可以在照片完成拍摄之前再次触摸屏幕。 所以,camera.takeP ...
  • 此代码假定您可以将result.width设置为某个动态计算的值。 这不适用于所有设备。 result 必须是getSupportedPreviewSizes()返回的值之一,以便在所有设备上可靠地工作,而在您的情况下,它不一定是这些值之一。 This code assumes that you can just set result.width to some dynamically-computed value. This will not work on all devices. The result ...
  • 此类在API级别21中已弃用。我们建议将新的android.hardware.camera2 API用于新的应用程序。 结果是不推荐使用Camera.Parameters。 Android开发者 - Camera.Parameters 对于API级别> 21的设备,您应该使用它: Android开发者 - android.hardware.camera2 This class was deprecated in API level 21. We recommend using the new android ...
  • 好的, 我想我得到了一个解决方案,虽然我不确定它是最好的解决方案。 我注意到在onPause()中释放旧的后,我从未告诉我的应用程序创建新预览。 我认为Android会处理这个问题,因为文档总是说没有必要重做第一次创建应用程序的设置。 显然,我误解了他们(虽然他们的意思是什么?)。 所以我在onPause()中添加了从我的Framelayout手动删除旧的CameraPreview对象,然后创建了一个新对象并将其添加到onResume()中的Framelayout。 @Override public voi ...
  • 您尝试将ImageButton强制转换为Button,因此请替换此代码: ImageButton cameraButton = (ImageButton) findViewById(R.id.button_camera); You are try to cast ImageButton as Button so replace this code : ImageButton cameraButton = (ImageButton) findViewById(R.id.button_camera);
  • 关闭活动后必须停止循环。 例如: public class YourActivity extends AppCompatActivity { private volatile boolean isStopped = false; @Override public void onStart() { super.onStart(); this.isStopped = false; } @Override public void onStop( ...
  • 如果要运行系统应用程序(通过Intent),则必须请求相应的权限,但正常权限除外。 注意 。 而且您必须记住,用户可以随时撤消授予的权限。 If you are going to run system applications (by Intent), then you must request the appropriate permissions, except Normal Permissions. NOTE. And you must remember that the user can at an ...
  • 似乎返回意图“ data ”为null 确保使用startActivityForResult和默认的相机应用程序。 只有在返回的Intent中传回缩略图时,默认的Android相机应用程序才会返回非空的intent。 如果您传递带有要写入的URL的EXTRA_OUTPUT,它将返回空意图,并且图片位于您传入的URL中。 Seems like the return intent "data" is null Make sure that you use startActivityForResult and t ...
  • 它听起来像你不允许系统更新自己已经创建了一个新的媒体文件。 这就是你的方法失败的原因。 您可以手动创建映像文件路径,以便在文件树上具有映像位置,也可以调用媒体服务来运行更新。 我总是创建自己的文件路径,因为较旧的手机需要更长时间才能使用媒体服务进行更新,因此在这种情况下您的方法将失败。 Apparently this crash is due to a known Samsung problem: it seems like you need to create a Uri before calling t ...
  • 经过大量的研究,我终于找到了问题所在。 问题在于FrameLayout,我不得不在Pause上删除它并在OnResume上重新创建它 @Override protected void onResume() { super.onResume(); mCamAsync = new CameraAsync(this);//Async task to get the camera instance mCamAsync.execute(); } @Override ...

相关文章

更多

最新问答

更多
  • 获取MVC 4使用的DisplayMode后缀(Get the DisplayMode Suffix being used by MVC 4)
  • 如何通过引用返回对象?(How is returning an object by reference possible?)
  • 矩阵如何存储在内存中?(How are matrices stored in memory?)
  • 每个请求的Java新会话?(Java New Session For Each Request?)
  • css:浮动div中重叠的标题h1(css: overlapping headlines h1 in floated divs)
  • 无论图像如何,Caffe预测同一类(Caffe predicts same class regardless of image)
  • xcode语法颜色编码解释?(xcode syntax color coding explained?)
  • 在Access 2010 Runtime中使用Office 2000校对工具(Use Office 2000 proofing tools in Access 2010 Runtime)
  • 从单独的Web主机将图像传输到服务器上(Getting images onto server from separate web host)
  • 从旧版本复制文件并保留它们(旧/新版本)(Copy a file from old revision and keep both of them (old / new revision))
  • 西安哪有PLC可控制编程的培训
  • 在Entity Framework中选择基类(Select base class in Entity Framework)
  • 在Android中出现错误“数据集和渲染器应该不为null,并且应该具有相同数量的系列”(Error “Dataset and renderer should be not null and should have the same number of series” in Android)
  • 电脑二级VF有什么用
  • Datamapper Ruby如何添加Hook方法(Datamapper Ruby How to add Hook Method)
  • 金华英语角.
  • 手机软件如何制作
  • 用于Android webview中图像保存的上下文菜单(Context Menu for Image Saving in an Android webview)
  • 注意:未定义的偏移量:PHP(Notice: Undefined offset: PHP)
  • 如何读R中的大数据集[复制](How to read large dataset in R [duplicate])
  • Unity 5 Heighmap与地形宽度/地形长度的分辨率关系?(Unity 5 Heighmap Resolution relationship to terrain width / terrain length?)
  • 如何通知PipedOutputStream线程写入最后一个字节的PipedInputStream线程?(How to notify PipedInputStream thread that PipedOutputStream thread has written last byte?)
  • python的访问器方法有哪些
  • DeviceNetworkInformation:哪个是哪个?(DeviceNetworkInformation: Which is which?)
  • 在Ruby中对组合进行排序(Sorting a combination in Ruby)
  • 网站开发的流程?
  • 使用Zend Framework 2中的JOIN sql检索数据(Retrieve data using JOIN sql in Zend Framework 2)
  • 条带格式类型格式模式编号无法正常工作(Stripes format type format pattern number not working properly)
  • 透明度错误IE11(Transparency bug IE11)
  • linux的基本操作命令。。。