【问题标题】:Obtaining the source IP and port of an INADDR_ANY client socket before the TCP three-way handshake?在 TCP 三向握手之前获取 INADDR_ANY 客户端套接字的源 IP 和端口?
【发布时间】:2015-06-02 14:43:30
【问题描述】:

我在Windows 7上,在connect之前使用bindSO_REUSEADDR,并将本地地址结构设置为IP地址INADDR_ANY和端口0(零),以便让操作系统选择客户端套接字的源详细信息。

首先,我了解到在连接到服务器之前无法获取源 IP,因为此时已选择它并且多个地址可能是有效的。但是端口是在连接之前选择的,那么有没有办法得到呢? (getsockname() 好像不行)。

其次,关于源IP,有没有办法在数据包发送到服务器之前得到它?我需要操作系统选择源 IP 和开始三次握手之间的特定时间。 connect() 函数支配两者。

【问题讨论】:

    标签: sockets tcp winsock winsock2


    【解决方案1】:

    我在 Windows 7 上,在 connectSO_REUSEADDR 之前使用 bind

    为什么在这种情况下使用SO_REUSEADDR?你不需要它,它对你正在尝试的东西没有任何意义。 SO_REUSEADDR 通常只能用于侦听套接字,而不是连接套接字。

    将本地地址结构设置为 IP 地址 INADDR _ANY 和端口 0(零),以便让操作系统为客户端套接字选择源详细信息。

    bind() 一个 client 套接字到INADDR_ANY:0 是没有意义的。您可以(并且应该)完全省略这样的 bind() 并保留套接字 unbound 直到调用 connect()唯一你应该曾经bind()一个客户端套接字的时间是如果你想将它绑定到一个特定本地 IP 和/或端口。但是在这种情况下你不会这样做,所以摆脱它。

    首先,我了解到在连接到服务器之前无法获取源 IP,因为此时已选择它并且多个地址可能是有效的。

    正确,除非你 bind() 到一个特定源 IP。

    但是在连接之前选择了端口

    如果套接字未绑定或绑定到源 IP INADDR_ANY 和/或源端口 0,则源 IP 和源端口都由 connect() 选择。所以在 connect() 之前你没有机会查询任何一个值选择他们。

    那么有没有办法得到它? (getsockname() 好像不行)。

    getsockname() 正是您所需要的。只要确保在connect() 首先成功连接到服务器之前,您不会调用它。这在getsockname() 文档中有说明:

    当在没有先进行绑定的情况下进行了连接调用时,此调用特别有用; getsockname 函数提供了确定系统已设置的本地关联的唯一方法。
    ...
    当套接字绑定到未指定的地址时,getsockname 函数并不总是返回有关主机地址的信息,除非套接字已通过 connect 或 accept 连接(例如,使用 ADDR_ANY)。 Windows Sockets 应用程序不得假定将指定地址除非套接字已连接。用于套接字的地址是未知的,除非套接字在多宿主主机中使用时已连接。如果套接字使用的是无连接协议,则在套接字上发生 I/O 之前,地址可能不可用。

    其次,关于源IP,有没有办法在数据包发送到服务器之前得到它?

    对于 TCP,您可以在 connect() 成功连接到服务器后立即使用 getsockname() 检索选定的源 IP。以前没有。

    我需要操作系统选择源 IP 和开始三次握手之间的特定时间。

    无法确定该细节。任何套接字应用程序都不应该需要这些细节。为什么需要它?

    【讨论】:

      【解决方案2】:

      我在 Windows 7 上,在连接 SO_REUSEADDR 之前使用绑定,并将本地地址结构设置为 IP 地址 INADDR _ANY 和端口 0(零),以便让操作系统选择客户端套接字的源详细信息.

      为什么?如果在connect(). 期间根本不调用bind(),就会发生这种情况。将客户端套接字绑定到INADDR_ANY 在任何情况下都是不正确的。如果不指定非零端口号,设置 SO_REUSEADDR 也没有任何意义。只需删除所有这些。

      首先,我了解到在连接到服务器之前无法获取源 IP,因为此时已选择它并且多个地址可能是有效的。

      正确。

      但是在连接之前就选择了端口,那么有没有办法获取呢?

      是的。 getsockname().

      (getsockname() 看起来不起作用)

      怎么办?

      其次,关于源IP,有没有办法在数据包发送到服务器之前得到它?

      您可以在connect() 成功后立即使用getsockname() 获取它,但这涉及向服务器发送数据包。

      我需要操作系统选择源 IP 和开始三次握手之间的特定时间。 connect() 函数支配两者。

      运气不好。

      【讨论】:

      • 没有希望了吗?那么预测源 IP 的函数呢?关于getsockname,我还没有尝试过,但我看到了一个包含IP的输出参数,并且在文档中写道,当我们使用INADDR_ANY时这是不可能的。
      • 您可以在 *nix 上使用的一个技巧是创建一个 UDP 套接字并 connect() 将其连接到对等地址 - 然后,getsockname() 将为您提供用于到达该目标的源地址。我不知道这在 Windows 上是否可行。 (如果您更改本地 IP 路由,或者有处理 TCP 和 UDP 不同的路由规则等,就会出现自然的竞争条件。)
      猜你喜欢
      • 2014-04-18
      • 1970-01-01
      • 2014-05-06
      • 1970-01-01
      • 2015-02-16
      • 1970-01-01
      • 2019-02-07
      • 2018-12-30
      • 1970-01-01
      相关资源
      最近更新 更多