2016-12-30 2 views
0

Есть ли параметр, который я могу использовать для предотвращения объединения нескольких TCP-пакетов в один буфер внутри обратного вызова Socket.BeginReceive?Socket.BeginReceive слияние TCP-пакетов

Реакция вашего коленного рефлектора будет заключаться в том, что я ничего не могу сделать, чтобы предотвратить разделение и слияние данных TCP, но это не то, что я прошу; Я могу отчетливо видеть, что отдельные пакеты принимаются в Wireshark, и моя единственная проблема - латентность, т. Е. Обрабатывать сегмент, как только он поступит. Это не значит, что я не знаю, как обрабатывать сегмент split/merged, но это означает, что я хочу избежать задержки.

Мой код выглядит следующим образом:

void WaitForData(ISocketInfo soc) 
{ 
    if (socket != null && socket.Connected) 
     socket.BeginReceive(buffer, 0, buffer.Length, 
      SocketFlags.None, OnPacketReceived, socket); 
} 

void OnPacketReceived(IAsyncResult asyn) 
{ 
    try 
    { 
     var socket = (ISocketInfo)asyn.AsyncState; 

     numberOfBytesReceived = socket.EndReceive(asyn); 
     if (numberOfBytesReceived > 0) 
     { 
      _queue.Enqueue(buffer, 0, numberOfBytesReceived); 
      OnNewDataReceived(); 
     } 

     WaitForData(socketInfo); 
    } 
    catch (SocketException ex) 
    { 
     Log.Warn("Socket error while receiving packet", ex); 
     Close(); 
    } 
} 

Когда я анализирую эти пакеты в WireShark, я могу увидеть отдельные пакеты TCP поступают каждые 50 мс, каждый из них (скажем) 100 байт. Но иногда в моем приложении есть задержка в 100 мс, а методы OnPacketReceived - 200 байт.

Поскольку WireShark подтверждает, что это не проблема с ОС/сетью, что может быть проблемой здесь? OnPacketReceived просто срабатывает в фоновом потоке, поэтому он не блокирует метод, и программа на самом деле не потребляет много CPU.

(Update)

Похоже, я не передать достаточно мой вопрос четко. Моя проблема заключается не в том, как анализировать данные, если они разделены по сегментам. Мой протокол хорошо определен (т. Е. START_COOKIE, LENGTH, DATA, CRC), и я вставляю данные в байтовый FIFO, как только я его получу (вызов _queue.Enqueue внутри фрагмента выше), поэтому я могу легко проанализировать его асинхронно.

Вопрос, если я вижу пакет нет. 1 (100 байт) при + 50 мс в Wireshark и номер пакета. 2 (100 байт) на + 100 мс в Wireshark, и мое приложение не блокирует метод OnPacketReceived и не потребляет процессор, почему .NET, каждый раз в то время, вызывает OnPacketReceived при + 100 мс и объединяет два пакета в один?

+3

Возможно, здесь проблема? _ Здесь нет проблем. TCP - бесконечный поток ** **, а поведение, которое вы описываете, является стандартным ** и ожидается **. Это зависит от вашей программы, чтобы иметь дело с частичными «сообщениями», и несколько «сообщений» получаются сразу. Либо с префиксом byte lengh, разделителями сообщений, либо комбинацией этих вещей. –

+0

[This] (http://stackoverflow.com/questions/16001434/async-tcp-server-message-framing-advice/16001812#16001812) ответ дает немного больше информации. – HABO

+0

@Idle_Mind: Я думаю, вы неправильно поняли вопрос. Я все равно размещаю все данные в буфер FIFO, и я могу легко разобрать его, формат четко определен. Но возникает вопрос: если Wireshark показывает ** два фактических отдельных TCP-пакета **, принимаемых сетевой картой, почему .NET создает дополнительную задержку и объединяет два пакета в один буфер? Меня беспокоит латентность, а не разбор. Во-вторых, TCP не является «бесконечным потоком», это протокол для передачи (потенциально) бесконечного потока данных в сегментах. – Lou

ответ

1

Вы можете получать меньше или больше, нет гарантии, что вы получите именно то, что было отправлено.

Из MSDN:

Там нет никакой гарантии, что отправляемые вами данные будут появляться в сети немедленно. Для повышения эффективности сети базовая система может задерживать передачу до тех пор, пока не будет собрано значительное количество исходящих данных. Успешное завершение метода BeginSend означает, что базовая система имеет место для буферизации ваших данных для сетевой отправки.

Here - хорошая статья, чтобы объяснить это и как вы можете исправить свою проблему.

+0

Спасибо, но это не то, что я спросил. Протокол данных хорошо определен с помощью start cookie/length/crc, поэтому я зачисляю данные в FIFO, и я разбираю его последовательно, независимо от того, как он разделяется/объединяется во время передачи. Мой вопрос: если Wireshark показывает два фактических отдельных TCP-пакета, принимаемых сетевой картой с задержкой 50 мс, как это делается.NET (время от времени) пропускает доставку первого пакета, создает дополнительную задержку и затем объединяет два пакета в один буфер, в то время как приложение практически ничего не делает для предотвращения мгновенной доставки? – Lou

0

TCP - это непрерывный поток данных по определению (это его главная особенность, чтобы было похоже, что пакетов вообще нет, в отличие от UDP). Таким образом, ваше программное обеспечение определяет формат сообщения. Вы можете:

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

Подводя итог, вы должны заботиться о разделении потока на сообщения. Или используйте HTTP, WebSockets или другие реализации формата сообщений поверх TCP.

 Смежные вопросы

  • Нет связанных вопросов^_^