- •Программирование в локальных сетях с использованием почтовых слотов
- •1 Почтовые слоты
- •1.1 Имена почтовых ящиков
- •1.2 Размеры сообщений
- •1.3 Общие сведения об архитектуре клиент-сервер
- •1.4 Сервер почтовых ящиков
- •1.5 Клиент почтовых ящиков
- •1.6 Дополнительные api-функции почтовых ящиков
- •1.7 Неспособность отменить блокирующие запросы ввода-вывода
- •1.8 Утечки памяти
- •2 Задания на выполнение лабораторной работы.
- •3 Контрольные вопросы
1.3 Общие сведения об архитектуре клиент-сервер
Почтовые ящики используют простую архитектуру клиент-сервер, в которой данные передаются от клиента серверу однонаправленно. Сервер отвечает за создание почтового ящика и является единственным процессом, который может читать из него данные. Клиенты почтовых ящиков - это процессы, открывающие экземпляры почтовых ящиков и единственные, имеющие право записывать в них данные.
1.4 Сервер почтовых ящиков
Для реализации почтового ящика нужно написать базовое серверное приложение, в котором выполнить следующие действия.
1. Создать описатель почтового ящика с помощью API-функции CreateMailslot.
2. Получить данные от любого клиента путем вызова API-функции ReadFile с описателем почтового ящика в качестве параметра.
3. Закрыть описатель почтового ящика с помощью API-функции CloseHandle.
Таким образом, для разработки серверного приложения почтового ящика требуется совсем немного вызовов API-функций.
Серверные процессы создают почтовые ящики с помощью вызова API-функции CreateMailslot, которая определена следующим образом:
HANDLE CreateMailslot(
LPCTSTR IpName,
DWORD nMaxMessageSize,
DWORD lReadTlmeout,
LPSECURITY_ATTRIBUTES IpSecurityAttributes
);
Параметр IpName задает имя почтового ящика. Оно должно иметь следующий вид:
\\.\Mailslot\[путь]имя
В данном случае имя сервера представлено точкой, что означает локальный компьютер. Это необходимо, поскольку нельзя создать почтовый ящик на удаленном компьютере. В параметре IpName имя обязательно уникально, но может быть простым или включать полный путь.
Параметр nMaxMessageSize задает максимальный размер (в байтах) сообщения, которое может быть записано в почтовый ящик. Если клиент записывает сообщение большего размера, сервер не видит это сообщение. Если задать значение 0, то сервер будет принимать сообщения любого размера.
Операции чтения могут выполняться с блокировкой почтового ящика или без таковой, в зависимости от параметра lReadTimeout, задающего количество времени (в миллисекундах), в течение которого операции чтения ждут входящих сообщений. Значение MAILSLOT_WAIT_FOREVER позволит заблокировать операции чтения и заставит их бесконечно ожидать, пока входящие данные не станут доступны для чтения. Если задать значение 0, операции чтения возвращаются немедленно.
Параметр IpSecurityAttributes определяет права доступа к почтовому ящику. В Windows 95 и Windows 98 он должен иметь значение NULL, потому что в этих ОС система безопасности к объектам не применима. В Windows NT и Windows 2000 этот параметр реализован частично, поэтому следует также присвоить ему NULL.
Примечание. Не создавайте почтовые ящики с длинными именами.
Почтовый ящик относительно безопасен только при локальном вводе-выводе, когда клиент пытается открыть этот ящик, используя точку (.) в качестве имени сервера. Клиент может обойти систему безопасности, задав вместо точки фактическое имя севера, как при удаленном вызове ввода-вывода. Параметр IpSecurityAttributes не реализован для удаленного ввода-вывода в Windows NT и Windows 2000 из-за больших издержек, связанных с формированием аутентифицированного сеанса между клиентом и сервером при каждой отправке сообщения. Таким образом, почтовые ящики только частично соответствуют модели безопасности Windows NT и Windows 2000, реализованной в стандартных файловых системах. В итоге, любой клиент почтового ящика в сети может отправлять данные серверу.
После создания почтового ящика с действительным описателем можно читать данные. Сервер - единственный процесс, который может читать данные из почтового ящика. Для этого он должен вызвать Win32-функцию ReadFile, определенную следующим образом:
BOOL ReadFile(
HANDLE hFlle,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
);
CreateMailslot возвращает описатель hFile.
Параметры lpBuffer и nNumberOfBytesToRead определяют, сколько данных может быть считано из почтового ящика. Важно задать размер этого буфера большим, чем параметр nMaxMessageSize из API-вызова CreateMailslot. Кроме того, размер буфера должен превышать размеры входящих сообщений, иначе ReadFile выдаст код ошибки ERROR_INSUFFICIET_BUFFER.
Параметр lpNumberOfBytes возвращает количество считанных байтов по завершении работы ReadFile.
Параметр lpOverlapped позволяет считывать данные из почтового ящика асинхронно. Он использует Win32-механизм перекрытого ввода-вывода (overlapped I/O). По умолчанию, выполнение ReadFile блокирует (ожидает) ввод-вывод, пока данные не станут доступны для чтения. Перекрытый ввод-вывод применим только в Windows NT и Windows 2000, в Windows 95 или Windows 98 присвойте параметру lpOverlapped значение NULL.
