BindException: adresse som allerede er i bruk på en klient socket?

stemmer
2

Jeg har en klient-server-lagdelt arkitektur med at kunden stiller RPC-lignende forespørsler til serveren. Jeg bruker Tomcat å være vert for servlets, og Apache Httpclient å gjøre forespørsler til det.

Koden min går noe sånt som dette:

    private static final HttpConnectionManager CONN_MGR = new MultiThreadedHttpConnectionManager();
    final GetMethod get = new GetMethod();
    final HttpClient httpClient = new HttpClient(CONN_MGR);
    get.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
    get.getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT);

    get.setQueryString(encodedParams);
    int responseCode;
    try {
        responseCode = httpClient.executeMethod(get);
    } catch (final IOException e) {
        ...
    }
    if (responseCode != 200)
        throw new Exception(...);

    String responseHTML;
    try {
        responseHTML = get.getResponseBodyAsString(100*1024*1024);
    } catch (final IOException e) {
        ...
    }
    return responseHTML;

Det fungerer bra i en lett-lastet miljøet, men når jeg gjør hundrevis av forespørsler per sekund jeg begynner å se dette -

Caused by: java.net.BindException: Address already in use
    at java.net.PlainSocketImpl.socketBind(Native Method)
    at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:336)
    at java.net.Socket.bind(Socket.java:588)
    at java.net.Socket.<init>(Socket.java:387)
    at java.net.Socket.<init>(Socket.java:263)
    at org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:80)
    at org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:122)
    at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:707)
    at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:387)
    at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
    at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
    at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)

Noen tanker om hvordan å fikse dette? Jeg gjetter det er noe å gjøre med klienten prøver å gjenbruke flyktige klient-porter, men hvorfor skjer dette / hvordan kan jeg fikse det? Takk!

Publisert på 30/12/2009 klokken 00:11
kilden bruker
På andre språk...                            


5 svar

stemmer
1

Med hundrevis av tilkoblinger i sekundet, og uten å vite hvor lenge forbindelsene holde åpne, gjøre sine ting, lukke og få resirkulert, jeg mistenker at dette er bare et problem du kommer til å ha. En ting du kan gjøre er å ta BindExceptioni prøve blokk, bruke den til å gjøre alt du trenger å gjøre i bind-mislykket saken, og pakk hele samtalen i en whilesløyfe som er avhengig av et flagg som angir om bind lyktes. Av toppen av hodet mitt:

boolean hasBound = false;
while (!hasBound) {
    try {
        hasBound = true;
        responseCode = httpClient.executeMethod(get);
    } catch (BindException e) {
        // do anything you want in the bound-unsuccessful case
    } catch (final IOException e) {
        ...
    }
}

Oppdatere med spørsmålet: En nysgjerrig spørsmål: hva er det maksimale totalt og per-host antall tilkoblinger tillates av MultiThreadedHttpConnectionManager? I koden din, ville det være:

CONN_MGR.getParams().getDefaultMaxConnectionsPerHost();
CONN_MGR.getParams().getMaxTotalConnections();
Svarte 30/12/2009 kl. 00:23
kilden bruker

stemmer
0

Dermed har du sparken flere forespørsler enn TCP / IP-porter får lov til å bli åpnet. Jeg kan ikke gjøre Httpclient, så jeg kan ikke gå i detalj om dette, men i teorien er det tre løsninger på dette problemet:

  1. Maskinvarebasert: legge til en annen NIC (nettverkskort).
  2. Programvare basert: nære forbindelser direkte etter bruk og / eller øke timeout tilkobling.
  3. Plattform basert: øke mengden av TCP / IP-porter som tillates å bli åpnet. Kan være OS-spesifikke og / eller NIC driveren spesifikke. Det absolutte maksimum er 65 535, hvorav flere kan allerede være reservert / i bruk (for eksempel 80).
Svarte 30/12/2009 kl. 00:24
kilden bruker

stemmer
1

En veldig god diskusjon av problemet du kjører inn kan bli funnet her . På Tomcat side, som standard vil den bruke SO_REUSEADDR alternativet, som vil tillate tjeneren å bruke stikkontakter som er i TIME_WAIT. I tillegg vil Apache HTTP-klient som standard bruk Keep-Alives, og forsøke å gjenbruke tilkoblinger.

Problemene ser ut til å være forårsaket av ikke kalle releaseConnection på Httpclient. Dette er nødvendig for at forbindelsen skal brukes. Ellers vil forbindelsen forbli åpen til søppelinnsamler kommer og lukker den, eller serveren kobler keep-live. I begge tilfeller vil det ikke bli returnert til bassenget.

Svarte 30/12/2009 kl. 01:37
kilden bruker

stemmer
0

Så det viser seg at problemet var at en av de andre Httpclient tilfeller tilfeldigvis ikke var med MultiThreadedHttpConnectionManager jeg startes, så jeg hadde effektivt ingen hastighetsbegrensende i det hele tatt. Fikse dette problemet løst unntak blir kastet.

Takk for alle forslag, selv om!

Svarte 30/12/2009 kl. 23:29
kilden bruker

stemmer
0

Selv om vi påberope HttpClientUtils.closeQuietly (klient); men i koden i tilfelle du prøver å lese innhold fra HttpResponse enhet som Input contentStream = HttpResponse.getEntity (). getContent (), bør du lukke Input også da bare Httpclient forbindelse bli lukket.

Svarte 29/06/2017 kl. 15:24
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more