【发布时间】:2014-03-14 22:55:31
【问题描述】:
如何防止 TCP 进行多次套接字连接尝试?
背景
我正在尝试粗略估计到客户的往返时间。我必须使用的高级协议无法确定 RTT,也没有任何类型的无操作请求/响应流。所以,我试图直接从较低层获取信息。特别是,我知道客户端会主动拒绝特定端口上的 TCP 连接尝试。
Me -> Client: SYN
Client -> Me: ACK, RST
代码
long lStartTime = System.nanoTime() / 1000000;
long lEndTime;
// Attempt to connect to the remote party. We don't mind whether this
// succeeds or fails.
try
{
// Connect to the remote system.
lSocket.connect(mTarget, MAX_PING_TIME_MS);
// Record the end time.
lEndTime = System.nanoTime() / 1000000;
// Close the socket.
lSocket.close();
}
catch (SocketTimeoutException|IOException lEx)
{
lEndTime = System.nanoTime() / 1000000;
}
// Calculate the interval.
lInterval = lEndTime - lStartTime;
System.out.println("Interval = " + lInterval);
问题
使用 Wireshark,我看到对 lSocket.connect 的调用在放弃之前进行了三次(失败)尝试连接套接字 - 显然是任意的尝试间间隔(通常约为 300 毫秒)。
Me -> Client: SYN
Client -> Me: ACK, RST
Me -> Client: SYN
Client -> Me: ACK, RST
Me -> Client: SYN
Client -> Me: ACK, RST
问题
有没有办法让 TCP 在单个 SYN/RST 对之后放弃?
我浏览了一些 Java 代码。当AbstractPlainSocketImpl 上的评论说时,我想知道我是不是赢了……
/**
* The workhorse of the connection operation. Tries several times to
* establish a connection to the given <host, port>. If unsuccessful,
* throws an IOException indicating what went wrong.
*/
...但遗憾的是,没有证据表明该函数或我查看过的任何其他(非本地)函数中存在循环/重试。
这种重试行为实际上来自哪里?又如何控制?
替代品
我也可能对替代品持开放态度,但不是……
- 使用 ICMP 回显请求(ping)。我知道很多客户不会回复他们。
- 使用原始套接字。其中一个平台是 Windows,如今它严重限制了使用原始套接字的能力。 (我还认为,如果 Linux 网络堆栈陷入尝试使用原始套接字执行 TCP 的应用程序的交火,它会毫无帮助地跳入。)
- 使用 JNI,除非作为最后手段。我的代码需要在至少 2 个非常不同的操作系统上运行。
【问题讨论】:
-
呃,我不明白...如果您收到 RST,您通常会收到 ECONNREFUSED,Java 会将其包装在
SocketException中(不记得具体是哪个)跨度> -
我得到了异常(我最终进入了 IOException 分支),但只有在某个底层尝试并失败了 3 次之后。
标签: java sockets tcp language-agnostic