Pergunta

Esperemos que alguém pode nos ajudar como nós estamos chegando até a investigação pode ir!

Nós temos um servidor de soquete assíncrono simples escrito em C # que aceita conexões de uma aplicação web ASP.NET, é enviada uma mensagem, executa algum processamento (geralmente contra um DB, mas outros sistemas também) e, em seguida, envia uma resposta de volta para o cliente. O cliente é responsável por fechar a conexão.

Nós temos tido problemas em que se o sistema está sob carga pesada durante um longo período de tempo (geralmente dias), tomadas CLOSE_WAIT acumular na caixa do servidor (netstat -a) de tal forma que o processo não vai aceitar quaisquer outras ligações. Nesse ponto, temos de devolver o processo e fora dele é executado novamente.

Nós tentamos a execução de alguns testes de carga da nossa aplicação ASP.NET para tentar replicar o problema (porque inferir algum problema a partir do código não foi possível). Pensamos que conseguimos isso e acabou com um WireShark pacote traçar do problema que se manifesta como um SocketException em os logs do servidor socket:

System.Net.Sockets.SocketException: uma conexão existente forçosamente foi fechada pelo host remoto em System.Net.Sockets.Socket.BeginSend (Byte [] tampão, Int32 deslocamento, tamanho Int32, SocketFlags SocketFlags, AsyncCallback chamada de retorno, estado do objeto)

Eu tentei reproduzir o problema a partir do rastreamento de pacotes como um único processo de rosca falando diretamente com o servidor de soquete (usando o mesmo código do aplicativo ASP.NET faz) e sou incapaz.

Alguém tem alguma sugestão de próximas coisas para tentar, cheque ou coisas óbvias que podem estar fazendo de errado?

Foi útil?

Solução

Olhe para o diagrama

http://en.wikipedia.org/wiki/File:Tcp_state_diagram_fixed.svg

O seu cliente fechou a conexão chamando close (), que enviou FIN ao soquete do servidor, que ACKed a FIN eo Estado de que agora mudou para CLOSE_WAIT, e permanece assim a menos que os problemas de servidor close () chamada em que socket.

Seu programa servidor precisa detectar se o cliente tenha abortado a conexão e, em seguida, close () imediatamente para liberar a porta. Quão? Consulte a ler (). Após a leitura de fim-de-arquivo (ou seja, FIN é recebida), zero é retornado.

Outras dicas

Se o seu servidor está acumulando soquetes CLOSE_WAIT então ele não está fechando seu soquete quando a conexão está completa. Se você der uma olhada no diagrama de estado no comentário para Chris' post que você verá que as transições CLOSE_WAIT para LAST_ACK uma vez que o socket está fechado ea FIN foi enviada.

Você diz que é complexo para determinar onde fazer isso devido à natureza assíncrona? Isso não deve ser um problema, você deve fechar o socket se o retorno do seu recv retorna 0 bytes (assumindo que você tem mais nada a fazer uma vez que seu cliente fecha o seu lado da conexão). Se você precisa se preocupar em continuar a enviar, em seguida, fazer um desligamento (recv) aqui e fazer uma nota que seu cliente tenha fechado, uma vez que você é feito enviando fazer um desligamento (send) e um em Fechar.

Você pode ser a emissão de uma nova leitura no callback da leitura que retorna 0 indicando que o cliente tenha fechado e isso pode estar causando-lhe problemas?

O cliente é responsável por fechar a conexão.

Tanto o cliente eo servidor deve fechar e desligamento da tomada. Ou o cliente não está terminando o próximo (improvável - uma vez que teria que do finalizador run) ou o servidor não está sendo desligado da tomada (provável)

.
using (Socket s = new Socket(/* */)) {
  /* Do stuff */
  s.Shutdown(SocketShutdown.Both);
  s.Close();
}

Você não deve ser deixando a responsabilidade de fechar os sockets TCP somente até o cliente. O que acontece se o processo cliente / máquina trava?

Idealmente, você deve ter um limite de tempo no lugar de modo que, se o trânsito não é recebido em um socket conectado após um determinado período de tempo, então ele fica fechada pelo servidor.

Não importa o que acontece quando todas as operações no soquete tenha terminado pelo cliente, e não precisa fazer quaisquer operações mais lidos no soquete, o cliente deve emitir um comando de fechamento.

Esta emissão de comando de fechamento, simplesmente diz ao ouvinte (o servidor) que as necessidades de conexão para ser desligado.

Em palavras simples, quando o servidor novamente emite um comando de leitura (listener.read () ou listener.beginread (...) em modo assíncrono), a leitura irá retornar a 0 bytes lidos, isso por si só indica que o necessidades de soquete para ser fechado pelo ouvinte como quaisquer outras operações no soquete deixou pelo cliente.

O CLOSE_WAIT são destinadas a pendurar ao redor por um tempo depois de um socket está fechado, para evitar re-utilizando o mesmo número de soquete e receber pacotes de conexão de idade. Isso só vai dar-lhe dor Se você estiver abrindo e fechando um número huuuuge de tomadas muito rapidamente.

EDIT -. Deve ser TIME_WAIT, não CLOSE_WAIT acima

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