Сокеты Windows. Работа сокетов с архивами
В этой статье объясняется, как объект CSocket, объект CSocketFile и объект CArchive объединяются для упрощения отправки и получения данных через сокет Windows.
В статье Windows Sockets: Пример сокетов с помощью архивов представляет функцию PacketSerialize
. Объект архива в PacketSerialize
примере работает так же, как архивный объект, переданный в функцию сериализации MFC. Важное отличие заключается в том, что для сокетов архив присоединяется не к стандартному объекту CFile (обычно связанному с файлом диска), но к объекту CSocketFile
. Вместо подключения к файлу CSocketFile
диска объект подключается к объекту CSocket
.
Объект CArchive
управляет буфером. Когда буфер архива хранения (отправки) заполнен, связанный CFile
объект записывает содержимое буфера. Очистка буфера архива, подключенного к сокету, эквивалентна отправке сообщения. Когда буфер архива загрузки (получения) заполнен, объект перестает считывать, CFile
пока буфер не будет доступен снова.
Класс CSocketFile
является производным отCFile
, но не поддерживает функции-члены CFile, такие как функции размещения (Seek
,, SetLength
GetLength
и т. д.), функции блокировки (LockRange
, UnlockRange
или GetPosition
функция). Весь объект CSocketFile должен выполнять запись или чтение последовательностей байтов в связанный объект или из негоCSocket
. Так как файл не участвует, такие операции, как Seek
и GetPosition
не имеет смысла. CSocketFile
является производным от CFile
, поэтому обычно он наследует все эти функции-члены. Чтобы предотвратить это, неподдерживаемые CFile
функции-члены переопределяются для CSocketFile
создания CNotSupportedException.
Объект 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
он не реализован как объект с двумя состояниями, то при обработке предыдущего уведомления можно получить дополнительные уведомления для того же типа события. Например, при обработке OnReceive
OnReceive
может появиться уведомление. В приведенном выше фрагменте кода извлечение str
из архива может привести к рекурсии. Переключение состояний предотвращает рекурсию, CSocket
предотвращая дополнительные уведомления. Общее правило не является уведомлениями в уведомлениях.
Примечание.
Можно CSocketFile
также использовать в качестве (ограниченного CArchive
) файла без объекта. По умолчанию CSocketFile
параметр bArchiveCompatible конструктора имеет значение TRUE. Это указывает, что объект файла предназначен для использования с архивом. Чтобы использовать объект файла без архива, передайте значение FALSE в параметре bArchiveCompatible .
В режиме "совместимого с архивом" CSocketFile
объект обеспечивает более высокую производительность и снижает опасность "взаимоблокировки". Взаимоблокировка возникает, когда отправка и получение сокетов ожидают друг друга или ожидают общего ресурса. Эта ситуация может произойти, если CArchive
объект работал с CSocketFile
тем, как он выполняется с CFile
объектом. С помощью CFile
архива можно предположить, что если он получает меньше байтов, чем запрошено, то достигнут конец файла. Однако данные CSocketFile
основаны на сообщениях; буфер может содержать несколько сообщений, поэтому получение меньше количества запрошенных байтов не означает конец файла. Приложение не блокируется в этом случае, так как оно может использовать CFile
, и оно может продолжать чтение сообщений из буфера до тех пор, пока буфер не будет пуст. Функция CArchive
IsBufferEmpty полезна для мониторинга состояния буфера архива в таком случае.
Дополнительные сведения см. в статье "Сокеты Windows: использование сокетов с архивами"