代码之家  ›  专栏  ›  技术社区  ›  Doug McClean

让客户提取数据

  •  1
  • Doug McClean  · 技术社区  · 15 年前

    我正在用C语言编写一个服务器,它创建一个(长的,甚至可能是无限的) IEnumerable<Result> 响应客户机请求,然后将这些结果流返回客户机。

    我可以设置它吗?这样,如果客户机读取速度慢(或者一次可能几秒钟都不读取),服务器就不需要一个线程暂停,等待缓冲区空间清空,这样它就可以将下两个线程 Result S,将它们序列化,然后将它们塞入网络?

    是这样吗? NetworkStream.BeginWrite 作品?文档对我来说不清楚什么时候调用回调方法。它基本上是立即发生的,只是在另一个线程上然后阻塞 EndWrite 等待实际的写作发生?当SocketsAPI中的某种低级缓冲区下溢时会发生这种情况吗?当数据实际写入网络时会发生这种情况吗?确认后会发生这种情况吗?

    我很困惑,所以有可能整个问题都是错误的。如果是这样的话,你能把我转过来,指出正确的方向来解决我所期望的是一个相当普遍的问题吗?

    2 回复  |  直到 15 年前
        1
  •  0
  •   Spencer Ruport    15 年前

    首先,当其他工作正在进行时,您的主线程可以继续执行的唯一方法是使用另一个线程。一根线不能同时做两件事。

    但是,我认为您试图避免的是与线程对象混淆,是的,这可以通过使用beginwrite实现。根据你的问题

    文件不清楚(对我来说) 关于回调方法将在何时 打电话。

    调用是在网络驱动程序将数据读取到其缓冲区后进行的。

    基本上是立即发生的吗? 就在另一条线上 EndWrite上的块正在等待 真的要写吗?

    不,直到它在网络驱动程序处理的缓冲区中。

    是不是在某种程度上 套接字API中的较低级别缓冲区 下溢?

    如果你的意思是它有空间容纳它,那么是的。

    当数据 实际写入网络?

    不。

    它是不是发生在 承认?

    不。

    编辑

    我个人会尝试使用线程。BeginWrite在幕后做了很多事情,你可能应该认识到…另外,我很奇怪,我喜欢控制我的线程。

        2
  •  2
  •   IRBMe    15 年前

    我会更详细地回答你问题的第三部分。

    MSDN文件规定:

    当应用程序调用BeginWrite时,系统使用单独的线程来执行指定的回调方法,并在EndWrite上阻塞,直到网络流发送请求的字节数或引发异常为止。

    据我所知,调用beginsend后是否立即调用回调方法取决于底层实现和平台。例如,如果IO完成端口在Windows上可用,则不会。线程池中的线程将在调用前阻塞。

    实际上,networkstream的beginwrite方法只是在.NET实现上调用基础套接字的beginsend方法。Mine使用底层的wsasend winsock函数和完成端口(如果可用)。这使得它比简单地为每个发送/写入操作创建自己的线程要高效得多,即使您要使用线程池也是如此。

    然后,socket.beginsend方法调用重叠pedasyncresult.checkAsyncCallOverlappedResult方法(如果wsasend的结果是iopending),后者反过来调用本机 RegisterWaitForSingleObject Win32函数。这将导致线程池中的一个线程阻塞,直到wsasend方法发出它已完成的信号,然后调用回调方法。

    networkstream.endsend调用的socket.endsend方法将等待发送操作完成。它必须这样做的原因是,如果IO完成端口不可用,那么将立即调用回调方法。

    我必须再次强调,这些细节是特定于我的.NET实现和我的平台的,但希望能给你一些启示。