如何确保数据在套接字编程中成功传递到另一端?
outStream.write()
不保证在另一端接收字节。我可以强制服务器发回一些确认数据,但是客户端应该等多久?如果我等待太短,可能只是当我在客户端抛出超时异常(然后显示错误对话框,但服务器实际接收到数据)时,数据被传递到服务器。另一方面,我不想等太多。
如果客户端等待一段时间并且如果收到确认,则向服务器发送第三个“提交”消息,然后服务器提供数据以供进一步处理(因此首先是客户端写入,然后是服务器回复,然后是客户端确认)。但话说回来,如果服务器上没有收到提交消息,客户端认为数据已成功发送,但服务器会在一段时间后忽略它,因为它没有收到提交消息。等等,弹跳永远不会结束......
这种情况一般如何处理?
我读到的每个教程都是关于创建/关闭套接字,在客户端发送数据并在服务器端接收数据。
如果您有解释此问题的博客链接(甚至是书籍),那也不错。
[编辑]
我应该澄清一些事情。我正在使用Java作为客户端和服务器,后来我将创建C#客户端。现在一切都很完美。客户端和服务器都在同一个局域网上,我从来没有遇到任何实际问题。上面解释的场景只是理论上的,因为我想尽可能多地介绍,包括错误处理。
我知道TCP保证传递,但在Java中,out.write()
在基础TCP传递或失败之前不会阻塞,然后继续执行或抛出异常。它只是继续执行,我不知道发送是否失败。没有回调函数。我从套接字编程开始,所以也许有一个我不知道的非常简单的解决方案。我需要做的就是确保客户端知道服务器收到了消息(如果可能的话)。
答案 0 :(得分:1)
如果您对可靠性有这种极端需求,则需要将其构建到您的应用程序和协议中。我过去做过的一种方法如下。
假设您有一个“对象”流(此处以对您的应用程序有意义的任何方式定义的对象)需要从客户端C传送到服务器S.将唯一标识符与客户端上的每个对象相关联。然后让C将每个对象及其标识符发送给S.但是让C保留其对象的副本(在内存中,或在磁盘上,或任何有意义的内容)。
对于S接收的每个对象,它将对象与其唯一标识符一起存储在其自己的本地数据存储中,并向C发送回确认它接收到对象(使用标识符进行通信)。 C现在可以从其数据存储中删除该对象(严格来说,它也可以删除它在该对象之前发送的所有对象 - 因为TCP保证了顺序传递 - 但这使事情稍微复杂化。)
此过程可以无限期地继续,C永远不需要明确等待任何一个对象的确认。它只是维护每个对象的本地副本。只要连接保持不变,S就会不断确认它收到的每个对象。
如果连接因任何原因而中断,则C假定S自最近收到的确认后未收到它发送的任何对象。当重新建立连接时,C可能因此重新发送S先前收到的一些对象,但由于S将唯一标识符与每个对象一起存储,它只是再次确认它已收到该对象。
如果由于某种原因S挂起,那么最终客户端和服务器之间的缓冲区将填满,C send
将阻塞。客户可能需要为这种可能性做好准备。
在对象流的末尾 - 如果有结束 - C将需要等待最后一个对象被确认。没有办法解决这个问题,所以你需要决定在C放弃并宣布错误之前等待多长时间。
(当然,这完全是在应用程序层重复TCP在传输层所做的事情:确认实际收到的内容,发送方能够重新传输丢失的任何内容。)
答案 1 :(得分:0)
<强> TCP:强>
TCP 保证在OSI Model的第4层传送数据包。 TCP基于握手,接收方必须在该握手中确认分组的传送。在这种情况下,您的代码中存在任何错误,或者您的网络出现故障。如果您正在谈论数据包没有到达目的地,请确保已将TCP服务器正确绑定到端口,并且目标是正确的。在等待数据包到达时,请确保您有一个接收超时,以防止您的应用程序挂起接收。