Pergunta

É possível desarranjar em um soquete depois que você chama Listen (FD, Backlog)?

EDIT: Meu erro por não me deixar claro. Eu gostaria de ser capaz de iluminar temporariamente o soquete. Chamar Close () deixará o soquete no estado M2LS e me impedirá de reabri -lo (ou pior, algum programa nefasto pode se ligar a esse soquete)

Temporariamente desarrumado seria uma maneira (talvez não a melhor maneira) de sinalizar para um balanceador de carga a montante que este aplicativo não poderia aceitar mais solicitações no momento

Foi útil?

Solução

Algumas bibliotecas de soquete permitem que você rejeite especificamente as conexões recebidas. Por exemplo: GNU's Commonc ++: TCPSocket Class tem um rejeitar método.

Os soquetes BSD não têm essa funcionalidade. Você pode aceitar a conexão e depois imediatamente perto Enquanto deixa o soquete aberto:

while (running) {

  int i32ConnectFD = accept(i32SocketFD, NULL, NULL);
  while (noConnectionsPlease) {
    shutdown(i32ConnectFD, 2);
    close(i32ConnectFD);
    break;
  }

}

Outras dicas

Depois de fechar o soquete, seus programas ainda podem dizer que o soquete está "em uso", isso é por causa de alguma estranheza que eu não conheço exatamente. Mas a manpra sobre soquetes mostra que há uma bandeira para reutilizar o mesmo soquete, preguiçosamente chamado: "SO_REUSEADDR". Defina -o usando "setSockOpt ()".

Fecha-o. Como eu lembro;

close(fd);

Com base na sua versão editada da pergunta, não tenho certeza de que você precise "não usar" ou fechar (). Duas opções vêm à mente:

1) Depois de invocar o Listen (), as conexões não são realmente aceitas até (logicamente o suficiente) que você chama de aceitação (). Você pode "desarranjar" simplesmente ignorando a atividade do soquete e adiando qualquer aceitação () até que você esteja pronto para eles. Qualquer conexão de entrada tenta o backlog na fila criada quando a porta foi aberta no modo de escuta. Depois que a fila do backlog está cheia na pilha, novas tentativas de conexão são simplesmente jogadas no chão. Quando você retomar com aceits (), você despeda rapidamente o backlog e estará pronto para mais conexões.

2) Se você realmente deseja que a porta pareça completamente fechada temporariamente, pode aplicar dinamicamente o filtro de pacote de nível de kernel na porta para impedir que as tentativas de conexão de entrada atinjam a pilha de rede. Por exemplo, você pode usar o filtro de pacotes Berkeley (BPF) na maioria das plataformas *nix. Ou seja, você deseja soltar pacotes de entrada no porto de interesse usando os recursos do firewall da plataforma. Isso, é claro, varia de acordo com a plataforma, mas é uma abordagem possível.

I don't think it's a good way to signal an upstream load-balancer. It would have to actually send some connections to your server before the message got through - those connections would probably get rejected.

Likewise, any connections which were pending when you closed the listening socket will get closed with no data.

If you want to signal the upstream load balancer, you should have a protocol for doing that. Don't try to abuse TCP to do it.

Fortunately if the clients are normal web browsers, you can get away with an awful lot - simply closing sockets generally results in them retrying transparently to the user (to a point).

There is no explicit method to unlisten!

You can either close(fd) or shutdown(fd, how)

fd is the socket file descriptor you want to shutdown, and how is one of the following:

0 Further receives are disallowed

1 Further sends are disallowed

2 Further sends and receives are disallowed (like close())

At a basic level, sockets are either open or closed (we'll ignore the niceties of the TCP/IP state diagram here).

If your socket is closed, then nothing can send data to it. If it's open, then incoming data will be accepted and acknowledged by the TCP/IP stack until it's buffering algorithm cries "enough!". At that point, further data will not be acknowledged.

You have two choices that I can see. Either close() the socket when you want to "unlisten", and reopen it later - Use setsockopt() with the SO_REUSEADDR flag to allow you to rebind to the well-known port before TIME_WAIT2 expires.

The other choice is to keep the socket open but simply not accept() from it while you're 'busy'. Assuming you have an application-level acknowledge to requests, You load balancer would realise it's not getting a response and act accordingly.

Here's a rather ugly approach based on your edited question:

Open a socket for listening with a normal backlog. Proceed.

When you want to "shut down", open a 2nd one with a backlog of 1 and SO_REUSEADDR. Close the first one. When ready to resume, do another socket juggle to one with a normal backlog.

Picky details around draining the accept queue from the socket that you're closing will be the killer here. Probably enough of a killer to make this approach nonviable.

I don't necessarily think this is a good idea, but...

You might be able to call listen a second time. The POSIX spec doesn't say not to. Perhaps you could call it a second time with a backlog parameter of 0 when you want to "unlisten".

What happens when listen is called with a backlog of 0 seems to be implementation defined. The POSIX spec says it may allow connections to be accepted, which implies some implementations may choose to reject all connections if the backlog parameter is 0. More likely though, your implementation will choose some positive value when you pass in 0 (probably either 1 or SOMAXCONN).

The question didn't say what kind of socket. If it is a unix socket, you can stop and start listening with rename(2). You can also permanently stop listening with unlink(2), and since the socket remains open you can continue to service your backlog. This approach seems quite handy, though I have not seen used before and am just exploring it myself.

You already got some answers on the impossibility to do this via the socket API.

You can use other OS methods (i.e. Host firwewall/iptables/ipfilter) to set up a temporary reject rule.

I found that most load balancers are a bit limited in the possibilities they offer to recognize connection problems (most of them recognize a RST only in the connect probe, not as answer to a legit connection attempt.)

Anyway, if you are limited by the probes detecting the inavailability, you set up an application level probe which does a HTTP request or FTP login or similiar things it will recognize if you simply close after accept. It could even interpret error messages like "500 service not available", which seems cleaner to me anyway. With SNMP some load balancers can also use the result as a load hint.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top