简体   繁体   English

如何在不破坏连接的情况下发送和接收高达SO_SNDTIMEO和SO_RCVTIMEO的数据?

[英]How to send and receive data up to SO_SNDTIMEO and SO_RCVTIMEO without corrupting connection?

I am currently planning how to develop a man in the middle network application for TCP server that would transfer data between server and client. 我目前正在计划如何在中间网络应用程序中为TCP服务器开发人员,以便在服务器和客户端之间传输数据。 It would behave as regular client for server and server for remote client without modifying any data. 它将充当服务器的常规客户端和服务器的远程客户端,而无需修改任何数据。 It will be optionally used to detect and measure how long server or client is not able to receive data that is ready to be received in situation when connection is inactive. 在连接处于非活动状态时,可以选择使用它来检测和测量服务器或客户机无法接收准备接收的数据的时间。

I am planning to use blocking send and recv functions. 我打算使用阻止发送和接收功能。 Before any data transfer I would call a setsockopt function to set SO_SNDTIMEO and SO_RCVTIMEO to about 10 - 20 miliseconds assuming it will force blocking send and recv functions to return early in order to let another active connection data to be routed. 在进行任何数据传输之前,我将调用setsockopt函数将SO_SNDTIMEO和SO_RCVTIMEO设置为大约10到20毫秒,假设它将强制阻塞send和recv函数提早返回,以便路由另一个活动的连接数据。 Running thread per connection looks too expensive. 每个连接的运行线程看起来太昂贵。 I would not use async sockets here because I can not find guarantee that they will get complete in a parts of second especially when large data amount is being sent or received. 我不会在这里使用异步套接字,因为我无法保证它们会在几分之一秒内完成,特别是在发送或接收大量数据时。 High data delays does not look good. 高数据延迟看起来不太好。 I would use very small buffers here but calling function for each received byte looks overkill. 我会在这里使用很小的缓冲区,但是为每个接收到的字节调用函数看起来过于浪费。

My next assumption would be that is safe to call send or recv later if it has previously terminated by timeout and data was received less than requested. 我的下一个假设是,如果之前已因超时而终止并且收到的数据少于请求的数量,则可以稍后再调用send或recv。

But I am confused by contradicting information available at msdn. 但是我对msdn上可用的信息感到矛盾而感到困惑。

send function 发送功能

https://msdn.microsoft.com/en-us/library/windows/desktop/ms740149%28v=vs.85%29.aspx https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms740149%28v=vs.85%29.aspx

If no error occurs, send returns the total number of bytes sent, which can be less than the number requested to be sent in the len parameter. 如果未发生错误,则send返回已发送的字节总数,该总数可以小于len参数中请求发送的字节数。


SOL_SOCKET Socket Options SOL_SOCKET套接字选项

https://msdn.microsoft.com/en-us/library/windows/desktop/ms740532%28v=vs.85%29.aspx https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms740532%28v=vs.85%29.aspx

SO_SNDTIMEO - The timeout, in milliseconds, for blocking send calls. SO_SNDTIMEO-阻止发送呼叫的超时(以毫秒为单位)。 The default for this option is zero, which indicates that a send operation will not time out. 此选项的默认值为零,表示发送操作不会超时。 If a blocking send call times out, the connection is in an indeterminate state and should be closed. 如果阻塞的发送呼叫超时,则连接处于不确定状态,应将其关闭。

Are my assumptions correct that I can use these functions like this? 我的假设可以使用这些功能是否正确? Maybe there is more effective way to do this? 也许有更有效的方法可以做到这一点?

Thanks for answers 谢谢答案

While you MIGHT implement something along the ideas you have given in your question, there are preferable alternatives on all major systems. 当您可以按照问题中给出的想法实施某些操作时,在所有主要系统上都有更可取的替代方法。

Namely: 即:

  • kqueue on FreeBSD and family. 在FreeBSD和家庭上使用kqueue。 And on MAC OSX. 在MAC OSX上。
  • epoll on linux and related types of operating systems. Linux和相关类型操作系统上的epoll。
  • IO completion ports on Windows. Windows上的IO完成端口。

Using those technologies allows you to process traffic on multiple sockets without timeout logics and polling in an efficient, reactive manner. 使用这些技术,您可以处理多个套接字上的流量,而无需超时逻辑并以有效的反应方式进行轮询。 They all can be considered successors of the ancient select() function in socket API. 它们都可以视为套接字API中古老的select()函数的后继者。

As for the quoted documentation for send() in your question, it is not really confusing or contradicting. 至于您问题中send()引用的文档,它并没有真正引起混淆或矛盾。 Useful network protocols implement a mechanism to create "backpressure" for situations where a sender tries to send more data than a receiver (and/or the transport channel) can accomodate for. 有用的网络协议实现了一种机制,用于在发送方尝试发送的数据超出接收方(和/或传输通道)可容纳的范围的情况下创建“背压”。 So, an application can only provide more data to send() if the network stack has buffer space ready for it. 因此,如果网络堆栈已准备好缓冲区空间,则应用程序只能向send()提供更多数据。

If, for example an application tries to send 3Kb worth of data and the tcp/ip stack has only room for 800 bytes, send() might succeed and return that it used 800 bytes of the 3k offered bytes. 例如,如果某个应用程序尝试发送价值3Kb的数据,而tcp / ip堆栈仅具有800个字节的空间,则send()可能会成功并返回它使用了3k提供的字节中的800个字节。

The basic approach to forwarding the data on a connection is: Do not read from the incoming socket until you know you can send that data to the outgoing socket. 在连接上转发数据的基本方法是:在知道可以将数据发送到传出套接字之前,不要从传入套接字中读取数据。 If you read greedily (and buffer on application layer), you deprive the communication channel of its backpressure mechanism. 如果您贪婪地阅读(并在应用程序层上缓冲),则会使通信通道失去其反压机制。

So basically, the "send capability" should drive the receive actions. 因此,基本上,“发送能力”应该驱动接收动作。

As for using timeouts for this "middle man", there are 2 major scenarios: 对于此“中间人”使用超时,有两种主要方案:

  1. You know the sending behavior of the sender application. 您知道发送方应用程序的发送行为。 Ie if it has some intent on sending any data within your chosen receive timeout at any time. 即是否有意在任何时候在您选择的接收超时时间内发送任何数据。 Some applications only send sporadically and any chosen value for a receive timeout could be wrong. 某些应用程序仅偶尔发送,接收超时的任何选定值都可能是错误的。 Even if it is supposed to send at a specific time interval, your timeouts will cause trouble once someone debugs the sending application. 即使应该在特定的时间间隔发送,一旦有人调试了发送应用程序,超时也会给您带来麻烦。
  2. You want the "middle man" to work for unknown applications (which must not use some encryption for middle man to have a chance, of course). 您希望“中间人”适用于未知的应用程序(当然,中间人一定不能使用某种加密方法)。 There, you cannot pick any "adequate" timeout value because you know nothing about the sending behavior of the involved application(s). 在那里,您无法选择任何“足够的”超时值,因为您对所涉及的应用程序的发送行为一无所知。

As a previous poster has suggested, I strongly urge you to reconsider the design of your server so that it employs an asynchronous I/O strategy. 正如先前的海报所建议的那样,我强烈建议您重新考虑服务器的设计,以使其采用异步I / O策略。 This may very well require that you spend significant time learning about each operating systems' preferred approach. 这很可能需要您花费大量时间来学习每种操作系统的首选方法。 It will be time well-spent. 这将是度过的时间。

For anything other than a toy application, using blocking I/O in the manner that you suggest will not perform well. 对于除玩具应用程序以外的任何其他应用程序,以您建议的方式使用阻塞I / O都不能很好地执行。 Even with short timeouts, it sounds to me as though you won't be able to service new connections until you have completed the work for the current connection. 即使超时很短,在我看来,在完成当前连接的工作之前,您将无法为新连接提供服务。 You may also find (with short timeouts) that you're burning more CPU time spinning waiting for work to do than actually doing work. 您可能还会发现(短时超时)正在花费更多的CPU时间来等待工作而不是实际工作。

A previous poster wisely suggested taking a look at Windows I/O completion ports. 以前的海报明智地建议您看一下Windows I / O完成端口。 Take a look at this article I wrote in 2007 for Dr. Dobbs. 看看我2007年为Dobbs博士写的这篇文章。 It's not perfect, but I try to do a decent job of explaining how you can design a simple server that uses a small thread pool to handle potentially large numbers of connections: 这不是完美的,但是我尝试做一个不错的工作来解释如何设计一个使用小线程池来处理潜在大量连接的简单服务器:

Windows I/O Completion Ports http://www.drdobbs.com/cpp/multithreaded-asynchronous-io-io-comple/201202921 Windows I / O完成端口http://www.drdobbs.com/cpp/multithreaded-asynchronous-io-io-comple/201202921

If you're on Linux/FreeBSD/MacOSX, take a look at libevent: 如果您使用的是Linux / FreeBSD / MacOSX,请查看libevent:

Libevent http://libevent.org/ Libevent http://libevent.org/

Finally, a good, practical book on writing TCP/IP servers and clients is "Practical TCP/IP Sockets in C" by Michael Donahoe and Kenneth Calvert. 最后,一本关于编写TCP / IP服务器和客户端的实用书籍,是Michael Donahoe和Kenneth Calvert撰写的“ C中的实用TCP / IP套接字”。 You could also check out the W. Richard Stevens texts (which cover the topic completely for UNIX.) 您还可以查看W. Richard Stevens的文本(完整涵盖了UNIX主题。)

In summary, I think you should take some time to learn more about asynchronous socket I/O and the established, best-of-breed approaches for developing servers. 总而言之,我认为您应该花一些时间来了解有关异步套接字I / O和用于服务器开发的已建立的最佳方法的更多信息。

Feel free to private message me if you have questions down the road. 如果您有疑问,请随时私下给我发消息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 您可以在boost asio中设置SO_RCVTIMEO和SO_SNDTIMEO套接字选项吗? - can you set SO_RCVTIMEO and SO_SNDTIMEO socket options in boost asio? 为什么windows udp接收套接字的超时总是比SO_RCVTIMEO设置的时间长500毫秒? - Why is the timeout on a windows udp receive socket always 500ms longer than set by SO_RCVTIMEO? setockopt参数SO_RCVTIMEO中的阻塞意味着什么 - what does blocking means in setsockopt parameter SO_RCVTIMEO SO_RCVTIME和SO_RCVTIMEO不会影响Boost.Asio操作 - SO_RCVTIME and SO_RCVTIMEO not affecting Boost.Asio operations Socket SO_RCVTIMEO 超时是 C++/VC++ 中设置值的两倍 - Socket SO_RCVTIMEO Timeout is double the set value in C++/VC++ 套接字:如何在客户端接收/解析数据时将数据发送到客户端而无需“等待” - Sockets: How to send data to the client without 'waiting' on them as they receive/parse it 如何在不破坏数据的情况下将缓冲区投射到结构? - How would one cast a buffer to a struct without corrupting the data? 如何通过串行终端检索数据而不破坏其在嵌入式 GNU ARM 中的基本价值? - How can I retrieve data through a serial terminal without corrupting its fundamental value in GNU ARM embedded? 如何设置函数指针参数,使其接受任何内容 - How to set up a function pointer parameter so it accepts anything 将原始数据“签名”写入磁盘而不会损坏文件系统 - Writing raw data “signature” to disk without corrupting filesystem
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM