TMt*_*ech 7

几周前我在实施VoIP服务器时也遇到了同样的问题.花了好几天后,我可以想出一个解决方案.正如许多其他人所提到的那样,没有任何直接的系统调用来完成这项工作.代替,

  1. 您可以检查我们是否在收到ACK带有TCP_INFO选项的数据包后收到了.
  2. 如果我们还没有收到ACK,请等待几毫秒再检查一下.

这可能会持续到超时为止.您必须将其实现为send()调用的包装函数.你需要tcp_info结构来自<netinet/tcp.h>.它是用于保存有关tcp连接的信息的数据结构.

这是伪代码

int blockingSend(const char *msg, int msglen, int timeout) {

    std::lock_guard<std::mutex> lock(write_mutx);

    int sent = send(sock_fd, msg, msglen,  0); 

    tcp_info info;
    auto expireAt = chrono::system_clock::now() + chrono::milliseconds(timeout);
    do {
        this_thread::sleep_for(milliseconds(50));
        getsockopt(sock_fd,SOL_TCP, TCP_INFO, (void *) &info, sizeof(info));

      //wait till all packets acknowledged or time expires
    } while (info.tcpi_unacked > 0 && expireAt > system_clock::now());

    if(info.tcpi_unacked>0) {
        cerr << "no of unacked packets :" << info.tcpi_unacked << endl;
        return -1;
    }
    return sent;
}
Run Code Online (Sandbox Code Playgroud)

tcpi_unacked成员保存未确认连接的数据包数.如果您在send()调用后不久读取它,它将包含分组数据包的数量,该数量等于发送的数据包数量.随着时间的推移,未打包的数量将减少到零.因此,您需要定期检查其值,tcpi_unacked直到达到零.如果连接是半开的,你将永远不会ACK在导致无限循环时收到s.对于这种情况,您可能需要添加上面实现的超时机制.

尽管很久以前就提出过这个问题,但这个答案可能会帮助那些遇到同样问题的人.我必须提一下,除了这个解决方案,这个问题可能有更准确的解决方案.因为我是系统编程和C/C++的新手,所以我可以想出来.


小智 6

TCP通常要求您在应用程序级别同步接收方和发送方.SO_SNDBUF调整或TCP_NODELAY单独组合不可能完全解决问题.这是因为在send()阻止之前可以"飞行"的数据量或多或少等于以下总和:

  1. 发送方发送缓冲区中的数据,包括由Nagle算法延迟的小数据片段,
  2. 未确认的正在进行的数据包中携带的数据量,它随拥塞窗口(CWIN)和接收窗口(RWIN)大小而变化.当TCP在慢启动,拥塞避免,快速恢复和快速重传模式之间转换时,TCP发送器不断地将拥塞窗口大小调整到网络状况.和,
  3. 接收方的接收缓冲区中的数据,接收方的TCP堆栈已经发送了一个ACK,但应用程序尚未看到.

换句话说,在接收器停止从套接字读取数据之后,send()只会在以下情况下阻塞:

  1. 接收器的TCP接收缓冲区填充和TCP停止ACK,
  2. 发送方将未经ACK编辑的数据发送到拥塞或接收窗口限制,并且
  3. 发送方的TCP发送缓冲区填充或发送方应用程序请求发送缓冲区刷新.

TCP中使用的算法的目标是创建流动的字节流而不是数据包序列的效果.一般来说,它试图尽可能地隐藏传输量化为数据包的事实,而大多数套接字API反映了这一点.这样做的一个原因是套接字可能根本不在顶级TCP(或甚至IP)上实现:考虑使用相同API的Unix域套接字.

尝试依赖TCP的底层实现细节来实现应用程序行为通常是不可取的.坚持在应用层同步.

如果在您正在进行同步的情况下延迟是一个问题,您可能还想了解Nagle算法和延迟之间的交互,ACK这会在某些情况下引入不必要的延迟.


Jam*_*ack 0

为什么不直接使用阻塞套接字呢?

这可能有点过时,但这里有一些关于阻塞/非阻塞和重叠 IO 的解释。

http://support.microsoft.com/kb/181611

顺便说一句,如果我们知道您使用的是哪种语言和操作系统,这将有助于更好地显示代码片段。

  • 这不会有帮助。阻塞套接字会阻塞,直到您成功地将数据传递到操作系统网络堆栈,而不是直到您收到对方的确认...顺便说一句,我在 Linux 上使用 C... (5认同)