java 套接字绑定错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1085675/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 15:07:11  来源:igfitidea点击:

Socket Bind Error

javasockets

提问by klaus johan

I have a test application that opens a socket , sends something through this socket and then closes it . This is done in a loop for 5-10.000 times. The thing is that after 3,4000 iterations I get an error of this type :

我有一个测试应用程序,它打开一个套接字,通过这个套接字发送一些东西,然后关闭它。这是在循环中完成 5-10.000 次。问题是,经过 3,4000 次迭代后,我收到了这种类型的错误:

java.net.BindException: Address already in use: connect

I even set the socket to be used immediattly, but the error persists

我什至将套接字设置为立即使用,但错误仍然存​​在

try
{
     out_server.write(m.ToByteArray());
     socket_server.setReuseAddress(true);
     socket_server.close();
}
catch(Exception e)
{
     e.printStackTrace();
     System.out.println(i+" unable to register with the server");
}

What could I do to fix this ?

我能做些什么来解决这个问题?

回答by paxdiablo

I think you may be going too fast.

我想你可能走得太快了。

Most operating systems have a limit on the number of sockets they can have open at any one time but it's actually worse than that.

大多数操作系统对它们在任何时候可以打开的套接字数量都有限制,但实际上比这更糟糕。

When a socket is closed down, it is put in a special time-wait state for a certain amount of time. This is usually twice the packet time-to-live value and it ensures that there aren't still packets out in the network that are on the way to your socket.

当一个套接字关闭时,它会在一定时间内处于特殊的时间等待状态。这通常是数据包生存时间值的两倍,它可以确保网络中没有数据包正在发送到您的套接字。

Once that time expires, you can be sure that all packets out in the network have already died. The socket is placed in that special state so that packets that were out in the network when you shut it down can be captured and thrown away if they arrive before they die.

一旦该时间到期,您可以确定网络中的所有数据包都已经死亡。套接字处于这种特殊状态,以便在您关闭它时在网络中的数据包可以被捕获并在它们死之前到达时将其丢弃。

I think that's what's happening in your case, the sockets aren't being freed as quickly as you think.

我认为这就是你的情况,套接字没有你想象的那么快被释放。

We had a similar problem with code that opened lots of short-lived sessions. It ran fine for a while but then the hardware got faster, allowing many more to be opened in a given time period. This manifested itself as inability to open more sessions.

我们在打开大量短期会话的代码中遇到了类似的问题。它运行了一段时间,但后来硬件变得更快,允许在给定的时间段内打开更多。这表现为无法打开更多会话。

One way to check this is to do netstat -afrom the command line and see how many sessions are actually in the wait state.

检查这一点的一种方法是netstat -a从命令行执行并查看实际处于等待状态的会话数。

If that does turn out to be the case, there's a few ways to handle it.

如果情况确实如此,则有几种方法可以处理。

  • re-use your sessions, either manually or by maintaining a connection pool.
  • introduce a delay in each connection to try and stop reaching the saturation point.
  • go flat out until you reach saturation and thenmodify your behaviour, such as running your connect logic inside a while statement that retries for up to 60 times with a two-second delay each time before giving up totally. This lets you run at full speed, slowing down only if there's a problem.
  • 手动或通过维护连接池重用您的会话。
  • 在每个连接中引入延迟以尝试并停止达到饱和点。
  • 一直坚持到达到饱和,然后修改您的行为,例如在 while 语句中运行连接逻辑,该语句重试多达 60 次,每次延迟两秒,然后完全放弃。这让您可以全速运行,只有在出现问题时才减速。


That last bullet point deserves some expansion. We actually used a back-off strategy in our afore-mentioned application which would gradually lessen the load on a resource provider if it was complaining so, instead of 30 two-second delays, we opted for a one-second delay, then two seconds, then four and so on.

最后一点值得扩展。实际上,我们在上述应用程序中使用了退避策略,如果资源提供者抱怨,它会逐渐减轻资源提供者的负载,而不是 30 次两秒延迟,我们选择一秒延迟,然后两秒,然后四等。

The general process for a back-off strategy is as follows and it can be used in any case where there may be temporary shortages of a resource. The action alluded to in the pseudo-code below would be the opening of a socket in your case.

退避策略的一般过程如下,它可以用于任何可能出现资源暂时短缺的情况。在下面的伪代码中提到的操作将是在您的情况下打开一个套接字。

set maxdelay to 16 # maximum time period between attempts
set maxtries to 10 # maximum attempts

set delay to 0
set tries to 0
while more actions needed:
    if delay is not 0:
        sleep delay
    attempt action
    if action failed:
        add 1 to tries
        if tries is greater than maxtries:
           exit with permanent error
        if delay is 0:
            set delay to 1
        else:
            double delay
            if delay is greater than maxdelay:
                set delay to maxdelay
    else:
        set delay to 0
        set tries to 0

This allows the process to run at full speed in the vast majority of cases but backs off when errors start occurring, hopefully giving the resource provider time to recover. The gradual increase in delays allows for more serious resource restrictions to recover and the maximum tries catches what you would term permanent errors (or errors that are taking too long to recover).

这允许进程在绝大多数情况下全速运行,但在错误开始发生时退出,希望给资源提供者时间恢复。延迟的逐渐增加允许更严重的资源限制来恢复,并且最大尝试次数可以捕获您称之为永久性错误(或需要很长时间才能恢复的错误)。

回答by Stu Thompson

My suggestions:

我的建议:

  • flush the socket after the write
  • add a tiny sleep (~50ms?) at the end of the above method
  • 写入后刷新套接字
  • 在上述方法的末尾添加一个小睡眠(~50ms?)

@Pax has a good point about the state of the socket afterwards. Try your code, let it fail, and then do a netstatand analyze it (or post here)

@Pax 对之后的套接字状态有一个很好的观点。尝试你的代码,让它失败,然后做一个netstat并分析它(或在这里发布)

回答by Len Holgate

What operating system? If you're using windows, and I'm guessing you are, then there's a limit to the number of client connections that you can have (this is configured by the MaxUserPortregistry entry which just so happens to be 4000 by default; see http://technet.microsoft.com/en-us/library/aa995661.aspxand http://www.tech-archive.net/Archive/Windows/microsoft.public.windows.server.general/2008-09/msg00611.htmlfor details of changing it). That, coupled with the fact that you're initiating the socket close from your client and so accumulating sockets in TIME_WAITstate on your client is likely the cause of your problem.

什么操作系统?如果您使用的是 Windows,我猜您是,那么您可以拥有的客户端连接数是有限制的(这是由MaxUserPort注册表项配置的,默认情况下恰好是 4000;请参阅http: //technet.microsoft.com/en-us/library/aa995661.aspxhttp://www.tech-archive.net/Archive/Windows/microsoft.public.windows.server.general/2008-09/msg00611。有关更改它的详细信息,请参阅html)。再加上您从客户端启动套接字关闭的事实,因此在TIME_WAIT客户端上累积套接字状态可能是导致问题的原因。

Please note that the solution to the TIME_WAITaccumulation issue is NOT to fiddle with the TCP stack's parameters to make the problem go away. TIME_WAITexists for a very good reason and removing or shortening it will likely cause you new problems!

请注意,TIME_WAIT累积问题的解决方案不是摆弄 TCP 堆栈的参数以使问题消失。TIME_WAIT存在一个很好的理由,删除或缩短它可能会给你带来新的问题!

So, assuming you're on a Windows machine, step one is to tune your MaxUserPortvalue so that you have more dynamic ports available for your outbound connections. Next, if this doesn't fix things for you, you can think about which side of the connection should end up with the TIME_WAIT(assuming you can control the protocol used on your connections...) The peer that issues the 'active close' is the one that ends up with the TIME_WAITso if you can change things so that your servers issue the active close then the TIME_WAITsockets will accumulate on the server rather than on the client and this MAYbe better for you...

因此,假设您使用的是 Windows 计算机,第一步是调整您的MaxUserPort值,以便您有更多动态端口可用于出站连接。接下来,如果这不能为您解决问题,您可以考虑连接的哪一侧应该结束TIME_WAIT(假设您可以控制连接上使用的协议......)发出“主动关闭”的对等点是最后一个,TIME_WAIT所以如果你可以改变事情以便你的服务器发出主动关闭那么TIME_WAIT套接字将在服务器上而不是在客户端上累积,这可能对你更好......

回答by George Phillips

I agree with others that you're running out of socket endpoints. However, that's not 100% crystal clear from you example as presumably the exception is coming from a connect() or bind() call that may be underlying some other high-level Java method.

我同意其他人的观点,即您的套接字端点用完了。但是,从您的示例中,这并不是 100% 非常清楚,因为可能异常来自 connect() 或 bind() 调用,这些调用可能是其他一些高级 Java 方法的基础。

One should also underscore that running out of endpoints isn't some kind of bizzare restriction of the socket library but a pretty fundamental part of any TCP/IP implementation. You need to keep information about old connections around for a little while so that late arriving IP packets for an old connection are dropped.

还应该强调,耗尽端点并不是套接字库的某种奇怪的限制,而是任何 TCP/IP 实现的一个非常基本的部分。您需要保留有关旧连接的信息一段时间,以便丢弃旧连接的迟到的 IP 数据包。

setReuseAddress() corresponds to the low-level SO_REUSEADDR socket option and only applies to the server when it does a listen().

setReuseAddress() 对应于低级 SO_REUSEADDR 套接字选项,仅适用于执行 listen() 的服务器。

回答by poundifdef

I think this is the same as this question (and I've linked to my answer, which I think might possibly help.)

我认为这与这个问题相同(我已经链接到我的答案,我认为这可能会有所帮助。)

Java Bind Exception

Java 绑定异常

回答by Duck

If the sample code is actually how you are executing the loop, you may have things in the wrong order.

如果示例代码实际上是您执行循环的方式,那么您的顺序可能有误。

The java docsfor setReuseAddress say: The behaviour when SO_REUSEADDR is enabled or disabled after a socket is bound (See isBound()) is not defined.

setReuseAddress的java 文档说:未定义在绑定套接字后启用或禁用 SO_REUSEADDR 时的行为(请参阅 isBound())。

Try moving the call to somewhere before you bind() or connect().

在 bind() 或 connect() 之前尝试将调用移动到某个地方。

回答by Sunil Kumar Sahoo

sometime after using socket.close() will not close socket immediately and the loop executes (in loop it tries the socket connection witrh same ip and port ) much faster so please null the socket.

使用 socket.close() 后的某个时候不会立即关闭套接字并且循环执行(在循环中它尝试使用相同 ip 和端口的套接字连接)要快得多,所以请将套接字归零。

socket_server.close();

socket_server.close();

socket_server = null;

socket_server = null;

Thanks Sunil Kumar Sahoo

感谢 Sunil Kumar Sahoo