Существует ли способ заблокироваться на сокете, отправляют (), пока мы не получаем ack для того пакета?

Уже существует большое хорошее обсуждение здесь, и я немного опаздываю стороне, но я хотел добавить несколько точек сам.

  • коллектор Мусора никогда не будет непосредственно выполнять Расположить метод для Вас.
  • GC будет выполнять финализаторы, когда будет похоже на него.
  • Один общий шаблон, который используется для объектов, которые имеют финализатор, должен иметь его, называют метод, который условно определяется, как Располагают (bool располагающий) передающая ложь, чтобы указать, что вызов был выполнен из-за завершения, а не явное Располагают вызов.
  • Это вызвано тем, что не безопасно сделать любые предположения о других управляемых объектах при завершении объекта (они, возможно, были уже завершены).

class SomeObject : IDisposable {
 IntPtr _SomeNativeHandle;
 FileStream _SomeFileStream;

 // Something useful here

 ~ SomeObject() {
  Dispose(false);
 }

 public void Dispose() {
  Dispose(true);
 }

 protected virtual void Dispose(bool disposing) {
  if(disposing) {
   GC.SuppressFinalize(this);
   //Because the object was explicitly disposed, there will be no need to 
   //run the finalizer.  Suppressing it reduces pressure on the GC

   //The managed reference to an IDisposable is disposed only if the 
   _SomeFileStream.Dispose();
  }

  //Regardless, clean up the native handle ourselves.  Because it is simple a member
  // of the current instance, the GC can't have done anything to it, 
  // and this is the onlyplace to safely clean up

  if(IntPtr.Zero != _SomeNativeHandle) {
   NativeMethods.CloseHandle(_SomeNativeHandle);
   _SomeNativeHandle = IntPtr.Zero;
  }
 }
}

Это - простая версия, но существует много нюансов, которые могут сбить Вас с толку на этом шаблоне.

  • контракт для IDisposable. Расположите указывает, что должно быть безопасно звонить многократно (вызов Располагают на объекте, который был уже расположен, ничего не должен делать)
  • , Это может стать очень сложным для надлежащего управления иерархией наследования доступных объектов, особенно если различные слои представляют новые Доступные и неуправляемые ресурсы. В шаблоне выше Располагают (bool), является виртуальным, чтобы позволить этому быть переопределенным так, чтобы им можно было управлять, но я нахожу, что это подвержено ошибкам.

, По-моему, намного лучше полностью постараться не иметь любые типы, которые непосредственно содержат и доступные ссылки и собственные ресурсы, которые могут потребовать завершения. SafeHandles обеспечивают очень очевидный способ выполнения этого путем инкапсуляции собственных ресурсов в доступные, которые внутренне обеспечивают их собственное завершение (наряду со многими другими преимуществами как удаление окна во время P/Invoke, где собственный дескриптор мог быть потерян из-за асинхронного исключения).

Просто определение SafeHandle делает это Тривиальным:


private class SomeSafeHandle
 : SafeHandleZeroOrMinusOneIsInvalid {
 public SomeSafeHandle()
  : base(true)
  { }

 protected override bool ReleaseHandle()
 { return NativeMethods.CloseHandle(handle); }
}

Позволяет Вам упрощать содержание типа до:


class SomeObject : IDisposable {
 SomeSafeHandle _SomeSafeHandle;
 FileStream _SomeFileStream;
 // Something useful here
 public virtual void Dispose() {
  _SomeSafeHandle.Dispose();
  _SomeFileStream.Dispose();
 }
}
10
задан anon 14 August 2009 в 18:06
поделиться

6 ответов

Если вы говорите о TCP, то нет - ни один API сокетов, который я видел, не позволяет вам это сделать.

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

3
ответ дан 3 December 2019 в 21:22
поделиться

Подтверждение для пакета находится на транспортном уровне (значительно ниже уровня приложения). У вас даже нет гарантии, что весь ваш буфер принадлежит его собственному пакету в сети. Что вы пытаетесь сделать?

1
ответ дан 3 December 2019 в 21:22
поделиться

Если вы используете setsockopt () для понижения SO_SNDBUF до значения, достаточного только для отправки одного пакета, то следующий отправит ( ) на этом сокете должна блокироваться до тех пор, пока не будет подтвержден предыдущий пакет. Однако, согласно tcp (7) , размер буфера сокета должен быть установлен до listen () / connect () .

.
0
ответ дан 3 December 2019 в 21:22
поделиться

Преимущества:

  1. Гибкие и очень мощные возможности сопоставления.
  2. Кэширование.
  3. Прекрасная реализация UnitOfWork.
  4. Запрос на будущее ( статья ).
  5. Классы моделей - это POCO - что по сути означает, что вы можете легко реализовать антипаттер анемичной области.
  6. Перехватчики - вы можете выполнять своего рода аспектно-ориентированное программирование ... Например, очень легко реализовать прослушивание, регистрацию, авторизацию, проверку и т. Д. Для ваш домен.
  7. Lucene.NET и NHibernate хорошо интегрированы друг с другом, что дает вам очень быструю и эффективную реализацию полнотекстового индексирования.
  8. Это очень зрелый и популярный в корпоративной среде.
  9. Большое сообщество.

Недостатки:

  1. Уже упоминалась кривая обучения. Вы можете начать использовать NHibernate очень быстро, но вам потребуются месяцы, чтобы освоить его. Я настоятельно рекомендую прочитать книгу Manning NHibernate.

  2. Написание сопоставления XML может быть очень утомительным, особенно для больших баз данных с сотнями и тысячами таблиц, представлений и хранимых процедур. Да, есть инструменты, которые помогут вам сгенерировать эти сопоставления, но вам все равно придется проделать довольно много ручной работы. Fluent NHibernate , похоже, упрощает этот процесс, избавляясь от сопоставлений XML, как и Castle ActiveRecord (AR, хотя его невозможно использовать для анемичной области, поскольку вы определяете сопоставления в атрибутах в классах модели

  3. В некоторых сценариях производительность может быть низкой. Например, крупные оптовые операции. Для тех, кому, возможно, придется использовать IStatelessSession, но это неудобно, по крайней мере, чтобы сказать ...

0
ответ дан 3 December 2019 в 21:22
поделиться

Весь смысл использования TCP состоит в том, чтобы скрыть этот индивидуальный ACK от приложений. Если вам нужно обнаруживать каждый ACK, реализуйте свой собственный протокол, используя UDP или IP. TCP наверное излишество. Или вы можете подняться по стеку и использовать протокол вроде HTTP в качестве транспорта.

0
ответ дан 3 December 2019 в 21:22
поделиться

TCP обычно требует, чтобы вы синхронизировали получателя и отправителя на уровне приложения. Комбинации настроек SO_SNDBUF или TCP_NODELAY сами по себе вряд ли решат проблему полностью. Это связано с тем, что объем данных, которые могут быть «в полете» до того, как send () заблокируется, более или менее равен сумме:

  1. данных в буфере отправки передающей стороны, включая небольшие фрагменты данных задерживаются алгоритмом Нэгла ,
  2. Объем данных, переносимых в неподтвержденных пакетах в полете, который зависит от окна перегрузки ( CWIN ) и размеры окна приема ( RWIN ). Отправитель TCP постоянно настраивает размер окна перегрузки в соответствии с условиями сети, поскольку TCP переходит между режимами медленного запуска, предотвращения перегрузки, быстрого восстановления и быстрой повторной передачи. И,
  3. Данные в приемном буфере принимающей стороны, для которых TCP-стек получателя уже отправил ACK , но приложение еще не увидело.

Другими словами, после того, как получатель прекратит считывать данные из сокета, send () будет блокироваться только в следующих случаях:

  1. Приемный буфер TCP получателя заполняется и TCP останавливает ACK ,
  2. Отправитель передает не ACK данные до предела перегрузки или окна приема, и
  3. буфер отправки TCP отправителя заполняется или приложение отправителя запрашивает очистку буфера отправки.

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

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

Если задержка вызывает беспокойство в ситуации, когда вы выполняете синхронизацию, вы также можете прочитать о взаимодействиях между Nagle »

6
ответ дан 3 December 2019 в 21:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: