在Linux中,我如何知道某个TCP数据包是否收到了ACK?

时间:2009-01-14 14:29:43

标签: linux tcp

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

全文:

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

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

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

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

控制流程如下:

  1. Panasonic称Asterisk:它向Asterisk打开Session 1(TCP / 1720),并通过Session 1发送一条SETUP消息,其中包含Panasonic将收听的port 2
  2. Asterisk通过Session 1
  3. 向Panasonic发送了一条CALL PROCEEDING消息
  4. Panasonic开始收听port 2
  5. Panasonic通过Session 1发送TCP ACK。
  6. Asterisk在Session 2上打开TCP port 2
  7. 步骤2和3的顺序很重要:除非port 2收到CALL PROCEEDING消息,否则Panasonic不会收听step 2

    但在OpenH323代码中,step 2step 5距离我们只有几行。

    这就是为什么连接sometimes在调试模式下工作而quite never在发布中工作的原因。

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

    除了step 4中的ACK之外,没有其他消息从Panasonic发送,并且似乎Asterisk可能知道听到port 2的唯一方式是收到该ACK。

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

    所以问题再次出现:在step 2中通过TCP连接发送消息后,如何知道是否收到包含该消息的数据包的ACK?

3 个答案:

答案 0 :(得分:3)

在这种特定情况下,我会说您会发现tcp_info结构会保留非零tcp_info.tcpi_unacked。你可以通过getsockopt(TCP_INFO)得到这个。

注意:界面不稳定。

答案 1 :(得分:1)

TCP级别的ACK由操作系统发送,并且可以在进程读取数据之前发送。因此,如果您收到ACK,则并不意味着远程应用程序对该消息采取了行动,或者甚至通知它已存在。

想象一下:如果TCP确认我们是消息确认,那么应用程序应该读取()消息,处理消息(可能需要一段时间),然后调用“read_ok”系统调用。据我所知,使用标准套接字API是不可能的。

您可以使用SIOCOUTQ ioctl(man 7 tcp)检查是否有任何未包装的数据。但这不是你问题的可靠解决方案。

你确定h323应该如何工作吗?如果port2无效或被另一个连接占用怎么办?应该发回确认或错误。

答案 2 :(得分:0)

虽然松下正在使用可能解释它的专有操作系统,但时序似乎很奇怪。

澄清 - AIUI - 如果松下正在运行“正常”操作系统,那么它在第4阶段发送的ACK将在Panasonic的软件具有来自控制TCP套接字的read()数据之后立即发生。

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

基本上似乎松下在listen() read()消息之后才在第二个套接字上执行相当于CALL PROCEEDING的操作。它看起来像竞争条件 - 有时Open323会在另一端准备好之前尝试connect()

当发生这种情况时,你会在OpenH23结束时得到ECONNREFUSED吗?