NetworkStream.Write returns immediately - how can I tell when it has finished sending data?尽管有文档,但NetworkStream.Write似乎不会等到发送数据后再进行。相反,它将等待直到将数据复制到缓冲区中然后返回。该缓冲区在后台传输。 这是我目前的代码。我使用ns.Write还是ns.BeginWrite都无关紧要-两者都立即返回。 EndWrite也立即返回(这是有意义的,因为它正在写入发送缓冲区,而不是写入网络)。
我如何知道何时实际将数据发送到客户端? 我想在发送数据后等待10秒钟(例如)以等待服务器的响应,否则我会认为出了点问题。如果发送数据需要15??秒,那么它将始终超时,因为我只能从NetworkStream.Write返回时开始计数-这是在发送数据之前。我想从数据离开网卡开始算起10秒。 数据量和发送时间可能会有所不同-发送数据可能需要1秒,发送数据可能需要10秒,发送数据可能需要一分钟。服务器收到数据后确实会发送响应(这是一个smtp服务器),但是我不想永远等待我的数据格式错误并且响应永远不会到来,这就是为什么我需要知道是否m等待数据发送,或者我正在等待服务器响应。 我可能想向用户显示状态-我想显示"向服务器发送数据"和"等待服务器的响应"-我该怎么做? 我不是C#程序员,但是您提出这个问题的方式有点误导。对于"接收"的任何有用定义,知道何时"接收"数据的唯一方法是在协议中包含一条特定的确认消息,该消息指示数据已被完全处理。 数据不会完全"离开"您的网卡。考虑程序与网络关系的最佳方法是:
在"很多令人困惑的东西"中可能出现的事情的列表:
因此,如果您所在的虚拟机位于不同的操作系统下,则该虚拟机具有控制该虚拟机网络行为的软件防火墙-何时"真正"离开您的网卡?即使在最佳情况下,这些组件中的许多组件也可能会丢弃一个数据包,您的网卡将需要重新传输该数据包。第一次(不成功)尝试后,它是否"遗失"了您的网卡?大多数网络API都会拒绝,直到另一端发送TCP确认后才"发送"。 就是说,NetworkStream.Write的文档似乎表明,直到至少启动了"发送"操作,它才会返回:
当然,由于我上面给出的原因,"发送"有点模糊。也有可能数据将由您的程序"真正"发送并由对等程序接收,但是对等方将崩溃或不进行实际处理。因此,您应该对消息进行 TCP是一种"可靠"的协议,这意味着如果没有套接字错误,则将在另一端接收数据。我已经看到了很多尝试以更高级别的应用程序确认来猜测TCP,但是恕我直言,这通常是浪费时间和带宽。 通常,您描述的问题是通过正常的客户端/服务器设计来解决的,其最简单的形式就是这样... 客户端向服务器发送请求,并在套接字上进行阻塞读取,以等待某种响应。如果TCP连接有问题,则读取将中止。客户端还应该使用超时来检测服务器的任何与网络无关的问题。如果请求失败或超时,则客户端可以重试,报告错误等。 服务器处理完请求并发送响应后,它通常不再关心发生的事情-即使套接字在事务处理过程中消失了-因为由客户端来决定是否进行进一步的交互。就个人而言,我觉得成为服务器感到非常安慰。 :-) 通常,我建议无论如何都要从客户端发送确认。这样,您可以100%确保已正确接收数据。 我试图了解.NET NetworkStream设计器的意图,他们必须以这种方式进行设计。写入后,.NET不再处理要发送的数据。因此,合理的做法是立即返回Write(并且不久后将从NIC发送数据)。 因此,在您的应用程序设计中,除了尝试使其按自己的方式工作外,您还应遵循此模式。例如,在从NetworkStream接收任何数据之前可以使用更长的超时时间,以补偿命令离开NIC之前所花费的时间。 总之,在源文件中硬编码一个超时值是一种不好的做法。如果超时值是可在运行时配置的,那么一切应该正常。 我无法想到NetworkStream.Write不会尽快将数据发送到服务器的情况。除非出现严重的网络拥塞或断开连接,否则它应在合理的时间内最终到达另一端。您是否有协议问题?例如,使用HTTP时,请求标头必须以空行结尾,并且服务器将不会发送任何响应,直到响应发生为止-使用的协议是否具有类似的消息结束特性? 这是比原始版本更干净的代码,删除了委托,字段和Thread.Sleep。它在功能上完全相同。
看来我在撰写本文时修改了问题。 .WaitOne()可能会帮助您解决超时问题。可以传递一个超时参数。这是一个懒惰的等待-在结果完成或超时到期之前,不会再次调度线程。 如果我不得不猜测,一旦将缓冲区交给Windows Socket,NetworkStream就会认为数据已发送。因此,我不确定是否可以通过TcpClient完成所需的方法。
Bellow .net是使用TCP的Windows套接字。
编辑: 如何使用Flush()方法。
那应该确保在继续操作之前已写入数据。
也许尝试设置 |