C # Socket.BeginSend Иногда кажется, что ведет себя синхронно? - PullRequest
0 голосов
/ 27 октября 2010

При попытке отправить сообщение для очереди через вызов BeginSend, похоже, он ведет себя как блокирующий вызов.

Конкретно у меня есть:

public void Send(MyMessage message)
{
  lock(SEND_LOCK){
    var state = ...
    try {
      log.Info("Begin Sending...");
      socket.BeginSend(message.AsBytes(),0, message.ByteLength, SocketFlags.None, 
         (r) => EndSend(r), state);
      log.Info("Begin Send Complete.");
    }
    catch (SocketException e) {
      ...
    }
  }
}

Обратный вызов будет выглядеть примерно так:

  private void EndSend(IAsyncResult result) {
     log.Info("EndSend: Ending send.");
     var state = (MySendState) result.AsyncState;
     ...

     state.Socket.EndSend(result, out code);

     log.Info("EndSend: Send ended.");

     WaitUntilNewMessageInQueue();
     SendNextMessage();
  }

Большую часть времени это работает нормально, но иногда зависает. Регистрация указывает, что это происходит, когда BeginSend en EndSend исполняются в том же потоке . WaitUntilNewMessageInQueue блокируется до тех пор, пока в очереди не появится новое сообщение, поэтому при отсутствии нового сообщения оно может ждать некоторое время.

Насколько я могу судить, это не должно быть проблемой, но в некоторых случаях блоки BeginSend вызывают ситуацию взаимоблокировки, когда EndSend блокирует WaitUntilNewMessageInQueue (ожидается), но Send блокируется на BeginSend в ответ, так как кажется, что он ожидает обратного вызова EndSend te (не ожидается).

Такое поведение было не тем, чего я ожидал. Почему BeginSend иногда блокируется, если обратный вызов не возвращается своевременно?

Ответы [ 2 ]

2 голосов
/ 27 октября 2010

Прежде всего, почему вы блокируете свой метод Send?Блокировка будет снята до завершения отправки, поскольку вы используете BeginSend.В результате несколько отправок могут выполняться одновременно.

Во-вторых, не пишите (r) => EndSend(r), просто пишите EndSend (без параметров).

Thrid: Вы делаетеНе нужно включать сокет в вашем штате.Ваш EndSend метод работает как любой другой метод экземпляра.Поэтому вы можете получить доступ к полю socket напрямую.

Что касается ваших тупиков, трудно сказать.Ваш делегат может иметь к этому какое-то отношение (оптимизация компилятором / бегуном).Но я ничего не знаю в этой области.

Нужна дополнительная помощь?Опубликуйте больше кода.но я предлагаю вам исправить вышеуказанные проблемы (все четыре) и сначала попробовать еще раз.

1 голос
/ 27 октября 2010

В какой операционной системе вы работаете?

Вы уверены, что видите то, что думаете?

Примечания на странице MSDN скажем, что Send() МОЖЕТ заблокировать, если нет места в буфере ОС для инициализации асинхронной отправки, если вы не перевели сокет в неблокирующий режим.Может ли это быть так?Потенциально вы отправляете данные очень быстро и заполняете окно TCP одноранговому узлу?Если вы вломитесь в отладчик, что показывает стек вызовов?

Остальное - предположение, основанное на моем понимании основополагающих нативных технологий ...

Вероятно, заметки для Send()неправильный вывод отмены ввода-вывода в случае выхода из потока, это почти наверняка зависит от базовой ОС, так как это порт завершения ввода-вывода низкого уровня / перекрывающаяся проблема ввода-вывода, которая изменилась в Windows Vista (см. здесь: http://www.lenholgate.com/blog/2008/02/major-vista-overlapped-io-change.html) иучитывая, что они ошибаются в этом, они могут ошибаться в отношении того, как завершения (вызовы EndSend() отправляются в более поздних операционных системах). Начиная с Vista, вполне возможно, что завершения могут быть отправлены в потоке выдачи, если .NetОболочка сокетов включает правильные параметры сокета (см. здесь , где я говорю о FILE_SKIP_COMPLETION_PORT_ON_SUCCESS) ... Однако, если бы это было так, то, скорее всего, вы бы увидели это поведениеПервоначально большинство отправлений, скорее всего, завершатся «в очереди», и поэтому вы увидите, что большинство завершений происходит натот же поток - я почти уверен, что это НЕ так, и что .Net НЕ включает эту опцию, не спрашивая ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...