【发布时间】:2010-10-01 09:13:11
【问题描述】:
长话短说:在 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 的端口是在运行时选择的。
控制流程如下:
- Panasonic 调用 Asterisk:它打开
Session 1(TCP/1720) 到 Asterisk 并通过Session 1发送一条 SETUP 消息,其中包含 Panasonic 将侦听的port 2。 - Asterisk 通过
Session 1向 Panasonic 发送 CALL PROCEEDING 消息 - 松下开始收听
port 2 - Panasonic 通过
Session 1发送 TCP ACK。 - Asterisk 在
port 2上打开 TCPSession 2。
第 2 步和第 3 步的顺序很重要:Panasonic 不会收听 port 2,除非它在 step 2 上收到 CALL PROCEEDING 消息。
但在 OpenH323 代码中,step 2 和 step 5 仅相隔几行。
这就是连接sometimes 在调试模式下工作而quite never 在发布模式下工作的原因。
在数据包转储中可以清楚地看到。我做了一系列的实验,52个案例中有52个,如果step 5在step 4之前,连接失败;如果没有,则连接成功。
除了step 4 中的 ACK 之外,松下没有发送任何其他消息,而且似乎 Asterisk 知道 port 2 被监听的唯一方法是接收该 ACK。
当然我可以实现定时等待,但我想要一个更简洁的解决方案。
那么问题又来了:在step 2 中通过 TCP 连接发送消息后,我如何知道是否收到了对包含该消息的数据包的 ACK?
【问题讨论】:
-
被确认的消息不会告诉您由于接收到数据而发生了任何处理,只是表明 TCP/IP 堆栈已接收到数据。所以你试图测试错误的东西。
-
@DavidSchwartz 这是一个老问题,但出于好奇,我应该测试什么是正确的?我正在处理的是一个糟糕的旧硬件,它运行着一个未记录的自定义操作系统,而 ACK 是告诉另一个连接被监听的唯一方法,而且从经验上讲,这是一个非常可靠的方法。
-
@Quassnoi 如果操作系统没有记录和自定义,那么您很可能会倒霉。