Поделиться через


Сокеты Windows: как сокеты с архивами работают

В этой статье объясняется, как объект CSocket, объект CSocketFile и объект CArchive объединяются для упрощения отправки и получения данных через сокет Windows.

В статье Windows Sockets: Пример использования сокетов с архивами представлена PacketSerialize функция. Объект архива в PacketSerialize примере работает так же, как архивный объект, переданный в функцию сериализации MFC. Важное отличие заключается в том, что для сокетов архив присоединяется не к стандартному объекту CFile (обычно связанному с файлом диска), но к объекту CSocketFile . Вместо подключения к файлу CSocketFile диска объект подключается к объекту CSocket .

Объект CArchive управляет буфером. Когда буфер архива хранения (отправки) заполнен, связанный CFile объект записывает содержимое буфера. Очистка буфера архива, подключенного к сокету, эквивалентна отправке сообщения. Когда буфер архива загрузки (получения) заполнен, CFile объект перестает считывать, пока буфер не будет доступен снова.

Класс CSocketFile наследуется от CFile, но не поддерживает функции-члены класса CFile, такие как функции позиционирования (Seek, GetLength, SetLength и т. д.), функции блокировки (LockRange, UnlockRange) или функцию GetPosition. Объект CSocketFile должен только записывать или считывать последовательности байтов в/из связанного объекта CSocket. Так как файл не участвует, такие операции, как Seek и GetPosition не имеет смысла. CSocketFile является производным от CFile, поэтому обычно он наследует все эти функции-члены. Чтобы предотвратить это, неподдерживаемые CFile функции-члены переопределяются в CSocketFile, чтобы выбросить CNotSupportedException.

Объект CSocketFile вызывает функции-члены объекта CSocket для отправки или получения данных.

На следующем рисунке показаны связи между этими объектами на обеих сторонах связи.

CArchive, CSocketFile и CSocket.
CArchive, CSocketFile и CSocket

Цель этой очевидной сложности заключается в том, чтобы защитить вас от необходимости управлять деталями сокета самостоятельно. Вы создаете сокет, файл и архив, а затем начинаете отправлять или получать данные, вставляя их в архив или извлекая их из архива. CArchive, CSocketFile и CSocket управляют сведениями за кулисами.

Объект CSocket на самом деле является двухфакторным объектом: иногда асинхронным (обычным состоянием) и иногда синхронным. В асинхронном режиме сокет может получать асинхронные уведомления от фреймворка. Однако во время операции, такой как получение или отправка данных, сокет становится синхронным. Это означает, что сокет не получит дополнительных асинхронных уведомлений до завершения синхронной операции. Так как он переключает режимы, можно, например, сделать следующее:

void CMySocket::OnReceive(int nErrorCode)
{
   if (0 == nErrorCode)
   {
      CSocketFile file(this);
      CArchive ar(&file, CArchive::load);
      CString str;

      ar >> str;
   }
}

Если CSocket он не реализован как объект с двумя состояниями, то при обработке предыдущего уведомления можно получить дополнительные уведомления для того же типа события. Например, вы можете получить уведомление при обработке OnReceiveOnReceive. В приведенном выше фрагменте кода извлечение str из архива может привести к рекурсии. Переключение состояний предотвращает рекурсию, CSocket предотвращая дополнительные уведомления. Общее правило: никаких уведомлений в уведомлениях.

Замечание

CSocketFile можно также использовать как файл (ограниченный) без объекта CArchive. По умолчанию CSocketFile параметр bArchiveCompatible конструктора имеет значение TRUE. Это указывает, что объект файла предназначен для использования с архивом. Чтобы использовать объект файла без архива, передайте значение FALSE в параметре bArchiveCompatible .

В режиме "архивируемого" CSocketFile объект обеспечивает более высокую производительность и снижает опасность "взаимоблокировки". Взаимоблокировка возникает, когда отправляющие и получающие сокеты ожидают друг друга или ожидают доступ к общему ресурсу. Эта ситуация может произойти, если объект CArchive работал с CSocketFile так, как он работает с объектом CFile. С помощью CFile архив может предположить, что если он получает меньше байтов, чем запрошено, то достигнут конец файла. Однако данные основаны на сообщениях в CSocketFile; буфер может содержать несколько сообщений, поэтому если получено меньше запрошенных байтов, это не означает конец файла. Приложение не блокируется в этом случае, так как оно может использовать CFile, и оно может продолжать чтение сообщений из буфера до тех пор, пока буфер не будет пуст. Функция CArchive полезна для мониторинга состояния буфера архива в таком случае.

Дополнительные сведения см. в статье "Сокеты Windows: использование сокетов с архивами"

См. также

Сокеты Windows в MFC
CObject::Serialize