尽管有文档,NetworkStream.Write似乎不会等到数据发送完毕.相反,它等待数据被复制到缓冲区然后返回.该缓冲区在后台传输.
这是我目前的代码.我是否使用ns.Write或ns.BeginWrite并不重要 - 两者都立即返回.EndWrite也会立即返回(这是有意义的,因为它写入发送缓冲区,而不是写入网络).
bool done; void SendData(TcpClient tcp, byte[] data) { NetworkStream ns = tcp.GetStream(); done = false; ns.BeginWrite(bytWriteBuffer, 0, data.Length, myWriteCallBack, ns); while (done == false) Thread.Sleep(10); } public void myWriteCallBack(IAsyncResult ar) { NetworkStream ns = (NetworkStream)ar.AsyncState; ns.EndWrite(ar); done = true; }
如何判断数据何时实际发送到客户端?
我想在发送数据后等待10秒(例如)来自服务器的响应,否则我会假设出错了.如果发送我的数据需要15秒,那么它将始终超时,因为我只能从NetworkStream.Write返回时开始计数 - 这是在数据发送之前.我想从数据离开网卡开始计算10秒钟.
数据量和发送时间可能会有所不同 - 发送它可能需要1秒,发送它可能需要10秒,发送它可能需要一分钟.服务器在收到数据时会发送响应(它是一个smtp服务器),但如果我的数据格式错误且响应永远不会到来,我不想永远等待,这就是为什么我需要知道我是不是等待数据发送,或者我正在等待服务器响应.
我可能想向用户显示状态 - 我想显示"向服务器发送数据","等待服务器响应" - 我怎么能这样做?
我不是C#程序员,但你问这个问题的方式有点误导.对于"已接收"的任何有用定义,知道何时"接收"数据的唯一方法是在协议中具有指示数据已完全处理的特定确认消息.
确切地说,数据不会"离开"您的网卡.考虑您的计划与网络的关系的最佳方式是:
你的程序 - >很多令人困惑的东西 - >同行程序
一系列可能出现在"很多令人困惑的东西"中的东西:
CLR
操作系统内核
虚拟化网络接口
一个开关
一个软件防火墙
硬件防火墙
执行网络地址转换的路由器
对等端的路由器执行网络地址转换
因此,如果您使用的是托管在不同操作系统下的虚拟机,该虚拟机具有控制虚拟机网络行为的软件防火墙 - 何时数据"确实"离开了您的网卡?即使在最好的情况下,许多这些组件也可能丢弃一个数据包,您的网卡需要重新传输.第一次(不成功)尝试时,它是否"离开"了您的网卡?大多数网络API都会拒绝,在另一端发送TCP确认之前,它尚未"发送".
也就是说,NetworkStream.Write的文档似乎表明它至少在启动'send'操作之前不会返回:
Write方法将阻塞,直到发送所请求的字节数或抛出SocketException.
当然,由于我上面提到的原因,"被发送"有些模糊.还有可能数据将由您的程序"真正"发送并由对等程序接收,但对等体将崩溃或者实际上不会实际处理数据.所以,你应该做Write
一个跟随Read
只会被同行发出时,它已经实际处理的消息的消息的.
TCP是一种"可靠"协议,这意味着如果没有套接字错误,将在另一端接收数据.我已经看到了许多努力在二次猜测TCP与更高级别的应用程序确认,但恕我直言,这通常是浪费时间和带宽.
通常,您描述的问题是通过正常的客户端/服务器设计来处理的,最简单的形式就是这样......
客户端向服务器发送请求,并在套接字上执行阻塞读取,等待某种响应.如果TCP连接出现问题,则该读取将中止.客户端还应使用超时来检测服务器的任何非网络相关问题.如果请求失败或超时,则客户端可以重试,报告错误等.
一旦服务器处理了请求并发送了响应,它通常不再关心发生了什么 - 即使套接字在事务期间消失 - 因为由客户端来启动任何进一步的交互.就个人而言,我觉得成为服务器非常令人欣慰.:-)