2

长话短说:在 Linux 中,如何确保收到某个 TCP 数据包的 ACK 消息?

全文:

我正在调试 Asterisk/OpenH323 <-> Panasonic IP-GW16 问题。

H323 连接涉及两个会话:H225.0 和 H245。这些只是两个 TCP 会话,通过它们传输一些数据。

我们称它们Session 1为(对于 H225.0)和Session 2(对于 H245)。

Session 1具有众所周知的 TCP 端口号 1720,而端口号Session 2是在运行时选择的。

控制流程如下:

  1. Panasonic 调用 Asterisk:它打开Session 1(TCP/1720) 到 Asterisk 并发送一个 SETUP 消息Session 1,其中包含port 2Panasonic 将要收听的消息。
  2. Asterisk 向 Panasonic 发送 CALL PROCEEDING 消息Session 1
  3. 松下开始收听port 2
  4. Panasonic 通过 发送 TCP ACK Session 1
  5. AsteriskSession 2port 2.

第 2 步和第 3 步的顺序很重要:Panasonic 不会收听,port 2除非它在 ​​上收到 CALL PROCEEDING 消息step 2

但是在 OpenH323 代码中,step 2只有step 5几行。

这就是连接sometimes在调试模式下quite never工作并在发布时工作的原因。

在数据包转储中可以清楚地看到。我做了一系列的实验,在52个案例中,有52个,如果step 5在前面step 4,连接失败;如果没有,则连接成功。

除了 ACK 中的 ACK 之外,没有从 Panasonic 发送的其他消息step 4,而且似乎 Asterisk 知道port 2被监听的唯一方法是接收该 ACK。

当然我可以实现定时等待,但我想要一个更清洁的解决方案。

所以问题又来了:在通过 TCP 连接发送消息后step 2,我如何知道是否收到了包含该消息的数据包的 ACK?

4

3 回答 3

4

在这种特定情况下,我会说您会发现您的tcp_info结构将包含一个 nonzero tcp_info.tcpi_unacked。你可以通过getsockopt(TCP_INFO).

注意:显然界面不稳定。

于 2009-01-14T16:46:35.497 回答
2

A TCP-level ACK is sent by the operating system and can be sent before the data is read by the process. So if you receive the ACK it doesn't mean that the remote application acted on the message or was even notified of it's existence.

Just imagine: if TCP acks we're a message confirmation then the application should read() the message, process it (which can take a while) and then call a "read_ok" syscall. As far as I know this is impossible with the standard socket API.

You might be able to check if there's any unacked data with the SIOCOUTQ ioctl (man 7 tcp). But it's not reliable solution to your problem.

Are you sure this is how h323 is supposed to work? What if port2 is invalid or taken by another connection? A confirmation or error should be sent back.

于 2011-10-29T00:12:44.440 回答
0

时序看起来很奇怪,尽管如果松下使用专有的操作系​​统可能会解释它。

澄清一下——AIUI——如果松下运行的是“正常”操作系统,它在第 4 阶段发送的 ACK 将在松下的软件read()从控制 TCP 套接字获得数据后立即发生。

同样,在 Asterisk 服务器接收到来自 Panasonic 的 ACK 之前,对(在步骤 2 中)的 OpenH323 代码调用write()不应返回(假设它不是非阻塞套接字!)。 就是您应该知道已收到 ACK 的方式。

从本质上讲,松下似乎在收到消息之前并没有在listen()第二个插座上做相当于。它看起来像一个竞争条件 - 有时 Open323 会在另一端准备好之前尝试。read()CALL PROCEEDINGconnect()

当这种情况发生时,你是否ECONNREFUSED在 OpenH23 结束?

于 2009-01-14T16:49:51.293 回答