Manuseamento caiu pacotes TCP em C #

votos
6

Estou enviando uma grande quantidade de dados de uma só vez entre um cliente e servidor escrito C #. Ele funciona muito bem quando eu executar o cliente eo servidor na minha máquina local, mas quando eu colocar o servidor em um computador remoto na internet parece cair dados.

I enviar 20000 cordas usando o método socket.Send () e recebê-los usando um loop que faz socket.Receive (). Cada string é delimitada por personagens únicos que eu uso para contar o número recebido (este é o protocolo, se quiser). O protocolo é comprovada, em que, mesmo com mensagens fragmentadas cada corda está corretamente contados. Na minha máquina local eu recebo toda 20000, através da internet eu recebo alguma coisa entre 17.000-20.000. Parece ser pior a conexão mais lenta que o computador remoto tem. Para aumentar a confusão, ligar Wireshark parece reduzir o número de mensagens deixadas cair.

Primeiro de tudo, o que está causando isso? É um problema de TCP / IP ou algo de errado com o meu código?

Em segundo lugar, como posso contornar isso? Receber todos os 20000 cordas é vital.

Tomada receber código:

private static readonly Encoding encoding = new ASCIIEncoding();
///...
while (socket.Connected)
{
    byte[] recvBuffer = new byte[1024];
    int bytesRead = 0;

    try
    {
        bytesRead = socket.Receive(recvBuffer);
    }
    catch (SocketException e)
    {
    if (! socket.Connected)
    {
        return;
    }
    }

    string input = encoding.GetString(recvBuffer, 0, bytesRead);
    CountStringsIn(input);
}

Tomada enviar o código:

private static readonly Encoding encoding = new ASCIIEncoding();
//...
socket.Send(encoding.GetBytes(string));
Publicado 26/08/2009 em 23:53
fonte usuário
Em outras línguas...                            


4 respostas

votos
4

Bem, há uma coisa errada com seu código para começar, se você está contando o número de chamadas para Receiveque completa: você parece estar assumindo que você vai ver como muitas Receivechamadas terminar como você fez Sendchamadas.

O TCP é um baseada em fluxo de protocolo - você não deve se preocupar com os pacotes individuais ou lê; você deve se preocupar com a leitura dos dados, esperando que às vezes você não receberá uma mensagem inteira em um pacote e às vezes você pode obter mais de uma mensagem em uma única leitura. (Uma leitura pode não corresponder a um pacote, também).

Você deve ou prefixar cada método com seu comprimento antes de enviar, ou ter um delimitado entre as mensagens.

Respondeu 26/08/2009 em 23:57
fonte usuário

votos
3

Se você está perdendo pacotes, você verá um atraso na transmissão, uma vez que tem de voltar a transmitir os pacotes descartados. Isto poderia ser muito significativa, embora há uma opção de TCP chamado reconhecimento seletivo que, se suportado por ambos os lados, ele irá acionar um reenvio de apenas os pacotes que foram retiradas e não todos os pacotes desde a lançada. Não há nenhuma maneira de controlar isso em seu código. Por padrão, você pode sempre assumir que cada pacote é entregue para que TCP e se há alguma razão que não pode entregar todos os pacotes em ordem, a ligação vai cair, seja por um tempo limite ou por uma extremidade do connetion o envio de uma pacote RST.

O que você está vendo é provavelmente o resultado do algoritmo de Nagle. O que ele faz é em vez de enviar cada bit de dados como você publicá-la, ele envia um byte e aguarda um ACK a partir do outro lado. Enquanto espera, que agrega todos os outros dados que você deseja enviar e combina-lo em um grande pacote e, em seguida, envia-lo. Uma vez que o tamanho máximo para TCP é 65k, pode combinar um pouco de dados em um pacote, embora seja extremamente improvável que isso irá ocorrer, particularmente desde que o tamanho do buffer padrão de winsock é de cerca de 10k ou assim (I esquecer o valor exato). Além disso, se o tamanho da janela máximo do receptor é inferior a 65k, ele só irá enviar tanto como o último tamanho da janela anunciado do receptor. O tamanho da janela também afeta Nagle'

A razão que você vê isto é porque na internet, ao contrário de sua rede, que primeiro ack leva mais tempo para retornar assim que o algoritmo do Naggle agrega mais de seus dados em um único pacote. Localmente, o retorno é efetivamente instantâneo por isso é capaz de enviar os seus dados tão rapidamente como você pode publicá-la à tomada. Você pode desativar o algoritmo de Naggle no lado do cliente usando SetSockOpt (winsock) ou Socket.SetSocketOption (Net), mas eu recomendo que você NÃO desativar Naggling no soquete a menos que você está 100% certo que você sabe o que está fazendo. É lá por uma razão muito boa.

Respondeu 27/08/2009 em 00:09
fonte usuário

votos
3

Definitivamente não é culpa do TCP. garantias TCP em ordem, entrega exatamente-uma vez.

Qual as cadeias são "perdidos"? Eu aposto que é os últimos; tente descarregar a partir do final de envio.

Além disso, o "protocolo" aqui (Eu estou tomando sobre o protocolo de camada de aplicação que você está inventando) está faltando: você deve considerar o envio do # de objetos e / ou do seu comprimento de modo que o receptor sabe quando ele está realmente feito recebê-los.

Respondeu 26/08/2009 em 23:55
fonte usuário

votos
1

Quanto tempo cada uma das cordas? Se eles não são exatamente 1024 bytes, eles vão ser fundidos pela pilha TCP / IP remoto em um grande fluxo, que você ler grandes blocos de em sua chamada Receber.

Por exemplo, usando três enviar chamadas para enviar "A", "B" e "C" muito provavelmente virá para o seu cliente remoto como "ABC" (como quer a pilha remoto ou a sua própria pilha vai tamponar o bytes até que sejam ler). Se você precisa de cada corda para vir sem ser fundida com outras cordas, olhar para a adição de um "protocolo" com um identificador para mostrar o início e final de cada corda, ou, alternativamente, configurar o soquete para evitar buffer e pacotes que combinam.

Respondeu 26/08/2009 em 23:55
fonte usuário

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