2015-03-20 6 views
0

Я работаю над клиентом C# TCP и отслеживаю свои пакеты с помощью Microsoft Network Monitor. Существует сервер, который в основном представляет собой черный ящик, посылает N количество пакетов (сейчас он находится в порядке 10-20) с задержкой от 0,1 мс до 1 мс между каждым из них и следующим.Socket не читает все входящие пакеты

Пакеты, которые читаются моим клиентом, находятся в порядке и, конечно, чаще всего поступают в более крупные куски, чем в Network Monitor, поскольку TCP получает поток. Моя проблема заключается в том, что некоторые пакеты не приходят (я проверял предыдущий фрагмент информации, чтобы убедиться, что его нет). Они также не хранятся в неправильном порядке.).

Возможно ли, что у моего клиента какая-то информация отсутствует? Часто ли отправляются пакеты? К сожалению, я не могу вмешиваться в их частоту. Я добавляю здесь некоторые из моего кода, если бы вы могли рассказать мне, почему пакеты, которые прибывают, не читаются, и как это решить, я был бы очень благодарен.

Это где я первый называют BeginReceive:

private static void AcceptCallback(IAsyncResult result) 
{ 
    ConnectionInfo connection = new ConnectionInfo(); 
    MensajeRecibido msj = new MensajeRecibido(); 
    try 
    { 
     // Finish Accept 

     Socket s = (Socket)result.AsyncState; 
     connection.Socket = s.EndAccept(result); 
     msj.workSocket = connection.Socket; 
     connection.Socket.Blocking = false; 
     connection.Buffer = new byte[255]; 
     lock (connections) connections.Add(connection); 

     // Start Receive 

     connection.Socket.BeginReceive(msj.buffer, 0, 
     msj.buffer.Length, SocketFlags.None, 
     new AsyncCallback(ReceiveCallback), msj); 
     // Start new Accept 
     serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), result.AsyncState); 
    } 
    catch (SocketException exc) 
    { 
     //Log here 
    } 
    catch (Exception exc) 
    { 
     //Log here 
    } 
} 

Это обратный вызов:

private async static void ReceiveCallback(IAsyncResult result) 
{ 
    MensajeRecibido mensaje = new MensajeRecibido(); 
    mensaje = (MensajeRecibido)result.AsyncState; 

    try 
    { 
     mensaje.workSocket.EndReceive(result); 
     mensaje.EstaCompleto(); 
     mensaje.workSocket.BeginReceive(mensaje.buffer, 0, 
     mensaje.buffer.Length, SocketFlags.None, 
     new AsyncCallback(ReceiveCallback), mensaje); 
    } 
    catch (SocketException) 
    { 
     //Log 
    } 
    catch (Exception) 
    { 
     //Log 
    } 
} 

И это метод EstaCompleto(), который в основном преобразует сообщение и добавляет его к списку. (Он возвращает истину или ложь, потому что это на самом деле означает идти в, если п, но пока я не избавиться от этой проблемы, которая на самом деле не служит никакой цели)

public bool EstaCompleto() 
{ 
    MensajeActual = Destuffing(ByteToFrame_Decoder(buffer)); //This translates the message to an understandable string 
    Mensajes.Enqueue(MensajeActual); 
    if(MensajeActual.Contains("<ETX>")) 
    { 
     return true; 
    } 
    else return false; 
} 

Edit 25/3/15: Вот остальная часть класса MensajeRecibido.

public class MensajeRecibido 
{ 

    public Socket workSocket = null; 
    // Size of receive buffer. 
    public const int BufferSize = 25500; 
    // Receive buffer. 
    public byte[] buffer = new byte[BufferSize]; 
    public string UltimoMensajeLeido = "0"; 
    public string MensajeActual = "0"; 
    public Queue<string> Mensajes = new Queue<string>(); 
    public IPAddress IPRack; 


    //******************************************************************* 

    public bool EstaCompleto() 
    ///See code in the previous sample 


    //******************************************************************* 
    public string ByteToFrame_Decoder(byte[] frame) 
    { 
     string answer = null; 
     UTF8Encoding ObjDecoder = new System.Text.UTF8Encoding(); 
     char[] array_chares = new char[frame.Length]; 
     string msj_neg = null; 
     string titlemsg = "Atención"; 
     try 
     { 
      int cant = ObjDecoder.GetChars(frame, 0, frame.Length, array_chares, 0); 
     } 
     catch (EncoderFallbackException EncFbackEx) 
     { 
      msj_neg = "No hay comunicación"; 
      // System.Windows.Forms.MessageBox.Show(msj_neg, titlemsg, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); 
     } 
     answer = decode_string(array_chares); 
     return answer; 
    } // fin método ByteToFrame_Decoder() 

    //******************************************************************* 
    public string Destuffing(string msjstuff) 
    { 
     string destuffed = null; 
     string matched = null; 
     string original = null; 
     int largo = msjstuff.Length; 

     for (int i = 0; i < (largo - 1); i++) 
     { 
      matched = msjstuff.Substring(i, 2); 
      original = msjstuff.Substring(i, 1); 
      if (original != " ") 
      { 
       switch (matched) 
       { 
        case "EX": 
         { original = "D"; i++; } break; 

        case "ex": 
         { original = "d"; i++; } break; 

        case "EE": 
         { original = "E"; i++; } break; 

        case "ee": 
         { original = "e"; i++; } break; 

        case " ": 
         { original = ""; i += 2; } break; 
       } 
       destuffed = destuffed + original; 
      } 
      else 
      { 
       i++; 
      } 

     } 
     destuffed = destuffed + ">"; 
     return destuffed; 

    } //fin método Destuffing() 
    //******************************************************************* 
    public static string decode_string(char[] ArrChar) 
    { 
     string text = null; 
     string reply = null; 
     foreach (char letter in ArrChar) 
     { 
      int value = Convert.ToInt32(letter); 
      string hexOutput = String.Format("{0:X}", value); // Convert the decimal value to a hexadecimal value in string form. 
      switch (hexOutput) 
      { 
       case "20": 
        text = " "; 
        break; 
       case "1": 
        text = "<SOH>"; 
        break; 
       case "2": 
        text = "<STX>"; 
        break; 
       case "3": 
        text = "<ETX>"; 
        break; 
       case "4": 
        text = "<EOT>"; 
        reply = reply + text; 
        goto Finish; 
       case "5": 
        text = "<ENQ>"; 
        break; 
       case "6": 
        text = "<ACK>"; 
        break; 
       case "15": 
        text = "<NAK>"; 
        break; 
       case "17": 
        text = "<ETB>"; 
        break; 
       case "1E": 
        text = "<RS>"; 
        break; 
       /*case "23": 
        text = "#"; 
        break; 
       case "24": 
        text = "$"; 
        break; 
       case "26": 
        text = "&"; 
        break;*/ 
       default: 
        text = letter.ToString(); 
        break; 
      } 
      reply = reply + text; 
     } 
    Finish: ; //salimos del foreach 
     return reply; 
    } //fin método decode_string() 
    //******************************************************************* 

} 

ответ

0

Без a good, minimal, complete code example, которая надежно демонстрирует проблему, что невозможно обеспечить точное исправление ошибки.

Однако из этого утверждения в вашем методе ReceiveCallback(), это ясно, что проблема:

mensaje.workSocket.EndReceive(result); 

Метод EndReceive() возвращает количество байт по причине: нет никакой гарантии, количества байтов, которые будут получать.

сети послушники программирования обычно жалуются на две различные модели поведения:

  1. Их код принимает только часть «пакета» (или «сообщение», или подобную терминологию).
  2. Их код не может получить некоторые из «пакетов», которые были отправлены.

Обе эти проблемы проистекают из одного источника: неспособность понять, что в протоколе TCP, нет такого понятия, как «пакет».

Это приложение, чтобы определить границу сообщения.Все, что дает вам TCP, является гарантией того, что если отправленные байты фактически получены, они будут получены в том же порядке, в котором они были отправлены, и если какой-либо данный байт получен, все ранее отправленные байты также были получены (т.е. отсутствие пробелов в данных).

Проблема № 1 выше происходит, когда TCP поставляет только часть того, что начинающий программист отправил как «пакет». Это совершенно законное поведение со стороны TCP, и до приложения отслеживать полученные данные до сих пор и выяснить, когда он получил целый «пакет».

Проблема №2 (это то, что вы испытываете) происходит, когда TCP поставляет два или более «пакетов» в одной операции приема. Опять же, это совершенно легально по части TCP, и до приложения обрабатывать полученные данные и идентифицировать, где заканчивается один «пакет», а следующий начинается.

Первый шаг к выполнению всего этого - фактически скопировать возвращаемое значение метода EndReceive() в переменную, а затем использовать это значение как часть обработки полученных данных. Поскольку ваш пример кода не сохраняет значение нигде или вообще не смотрит на него, я могу гарантировать, что вы неправильно обрабатываете границы «пакета» в своих данных.

Как вы должны справиться с этими границами? Понятия не имею. Это зависит от того, как вы отправляете данные, и как вы хотите обработать результаты. Без полного примера кода (как описано в ссылке, приведенной выше), это невозможно. Однако обратите внимание, что существует множество примеров того, как это сделать правильно. Надеюсь, теперь, когда вы знаете, что искать, вы сможете придумать исправление. Если нет, не стесняйтесь создавать хороший пример кода и задавать новый вопрос с просьбой о помощи в этом.

+0

Прежде всего, спасибо за минимальную полную ссылку кода, я раньше этого не видел. Было бы трудно воспроизвести его проблему для тех, кто не владеет оборудованием, с которым я общаюсь, и я боюсь, что мне не разрешено использовать IP-адрес для доступа к нему, что является довольно хлопотным. Я сохраняю информацию каждый раз на этих строках: MensajeActual = Destuffing (ByteToFrame_Decoder (buffer)); // Это переводит сообщение в понятную строку Mensajes.Enqueue (MensajeActual); И затем я проверяю очередь, чтобы узнать, что было прочитано. Я не получил два сообщения вместе, как я уже говорил. – Alex

+0

_ «Было бы трудно воспроизвести проблему» _ - тем не менее, для тех, кто может помочь с любым точным ответом, вы должны представить воспроизводимый случай. Если вы не можете, то это не правильный форум для получения помощи. –

+0

_ «Я храню информацию каждый раз на этих строках» _ - нет, не совсем. Тот факт, что вы не используете возвращаемое значение 'EndReceive()', означает, что он является _impossible_, чтобы остальная часть вашего кода работала правильно. Правильная реализация TCP не потеряет «пакеты», период. Если вы считаете, что это происходит, то либо вы имеете неправильную реализацию TCP (например, в «оборудовании»), либо просто не можете распознать объединенные «пакеты» в полученных вами данных. Я считаю последнее более вероятным сценарием, чем первое. –