我目前正在计划如何在中间网络应用程序中为TCP服务器开发一个 man,它将在服务器和客户端之间传输数据。它可以作为远程客户端的服务器和服务器的常规客户端,而无需修改任何数据。它可以选择用于检测和测量服务器或客户端在连接处于非活动状态时无法接收准备好接收的数据的时间。
我打算使用阻塞发送和recv函数。在进行任何数据传输之前,我会调用setsockopt函数将SO_SNDTIMEO和SO_RCVTIMEO设置为大约10-20毫秒,假设它将强制阻塞send和recv函数提前返回,以便让另一个活动连接数据被路由。每个连接运行线程看起来太贵了。我不会在这里使用异步套接字,因为我无法保证它们会在一秒钟内完成,特别是在发送或接收大量数据时。高数据延迟看起来不太好。我会在这里使用非常小的缓冲区,但是为每个接收到的字节调用函数看起来有点过分。
我的下一个假设是,如果之前因超时而终止并且收到的数据少于请求,则可以安全地调用send或recv。
但令我感到困惑的是与msdn。
提供的信息相矛盾发送功能
https://msdn.microsoft.com/en-us/library/windows/desktop/ms740149%28v=vs.85%29.aspx
如果没有错误发生,send返回发送的总字节数,即 可以小于len参数中请求发送的数量。
SOL_SOCKET套接字选项
https://msdn.microsoft.com/en-us/library/windows/desktop/ms740532%28v=vs.85%29.aspx
SO_SNDTIMEO - 阻止发送呼叫的超时(以毫秒为单位)。 此选项的默认值为零,表示发送 操作不会超时。如果阻塞发送呼叫超时,则 连接处于不确定状态,应该关闭。
我的假设是否正确,我可以使用这样的函数吗?也许有更有效的方法来做到这一点?
感谢您的回答
答案 0 :(得分:3)
虽然你可能会在你的问题中实现一些想法,但在所有主要系统上都有更好的选择。
即:
使用这些技术,您可以在没有超时逻辑的情况下处理多个套接字上的流量,并以高效,被动的方式进行轮询。它们都可以被认为是套接字API中古代select()
函数的后继者。
至于你问题中send()的引用文档,它并不是真的令人困惑或矛盾。有用的网络协议实现了一种机制,用于在发送方尝试发送比接收方(和/或传输信道)可以容纳的更多数据的情况下创建“背压”。因此,如果网络堆栈已准备好缓冲区空间,则应用程序只能为send()提供更多数据。
例如,如果应用程序尝试发送3Kb的数据并且tcp / ip堆栈只有800字节的空间,则send()
可能会成功并返回它使用了3k提供的字节中的800字节。 / p>
在连接上转发数据的基本方法是:在知道可以将数据发送到传出套接字之前,不要从传入套接字读取。如果您贪婪地阅读(以及应用程序层上的缓冲区),则会剥夺通信通道的反压机制。
基本上,“发送功能”应该驱动接收操作。
至于使用这个“中间人”的超时,有两个主要场景:
答案 1 :(得分:3)
正如之前的海报所建议的那样,我强烈建议您重新考虑服务器的设计,以便它采用异步I / O策略。这可能需要您花费大量时间来了解每个操作系统。首选方法。这将花费很多时间。
对于除玩具应用程序之外的任何其他内容,以您建议的方式使用阻止I / O将无法正常运行。即使时间很短,对我来说也好像在完成当前连接的工作之前无法为新连接提供服务。您可能还会发现(超时超时)您在等待工作时所花费的CPU时间比实际工作要多。
之前的海报明智地建议看看Windows I / O完成端口。看看我在2007年为Dobbs博士写的这篇文章。它并不完美,但我试着解释如何设计一个使用小线程池来处理潜在大量连接的简单服务器:
Windows I / O完成端口 http://www.drdobbs.com/cpp/multithreaded-asynchronous-io-io-comple/201202921
如果您使用的是Linux / FreeBSD / MacOSX,请查看libevent:
LIBEVENT http://libevent.org/
最后,关于编写TCP / IP服务器和客户端的一本好的,实用的书是" C"中的实用TCP / IP套接字。作者:Michael Donahoe和Kenneth Calvert。您还可以查看W. Richard Stevens的文本(完全涵盖UNIX的主题。)
总之,我认为您应该花一些时间来了解有关异步套接字I / O以及用于开发服务器的已建立的最佳方法的更多信息。
如果您有任何疑问,请随时向我发送私信。