Главная страница

Программирование в сетях Windows. Э. Джонс, Д. Оланд


Скачать 2.88 Mb.
НазваниеЭ. Джонс, Д. Оланд
АнкорПрограммирование в сетях Windows.pdf
Дата12.10.2017
Размер2.88 Mb.
Формат файлаpdf
Имя файлаПрограммирование в сетях Windows.pdf
ТипКнига
#9346
страница39 из 50
1   ...   35   36   37   38   39   40   41   42   ...   50

ГЛАВА 15 Элемент управления Winsock
469
Табл. 15-1. Свойства элемента управления Winsock
Имя свойства Тип возвра- Доступно
щаемого только
значения для чтения
Описание
BytesRecetved Long
Да
LocalHostName String Да
LocallP String Да
LocalPort
Protocol
Long
Long
Нет
Нет
RemoteHost String Нет
RemoteHostIP String
Да
RemotePort Long Нет
SocketHandle Long Да
State Integer Да
Возвращает количество байт, ожидаю- щих в буфере приема Для получения ожидающих данных воспользуйтесь методом GetData
Возвращает имя локального компьютера
Возвращает строку, содержащую IP- адрес локального компьютера в пред- ставлении с точечной нотацией
Возвращает или задает используемый локальный порт Если в качестве номера порта передать 0, система выберет дос- тупный порт произвольно Обычно так поступают только клиенты
Возвращает или задает используемый элементом управления протокол, под- держиваются лишь протоколы TCP и
UDP Протоколы обозначаются констан- тами sckTCPProtocol и sckUDPProtocol,
которым соответвуют значения О и 1
Возвращает или задает имя удаленного компьютера Можно использовать как обычное строковое представление имени, так и представление с точечной нотацией
Возвращает IP-адрес удаленного компь- ютера Для TCP-подключений значение данного поля задается после успешного установления соединения, для UDP-под- ключений — при наступлении события
DataAmval (поле будет содержать IP-ад- рес передающего компьютера)
Возвращает или задает удаленный порт,
к которому производится подключение
Возвращает значение, соответствующее описателю сокета
Возвращает состояние элемента управ- ления, являющееся перечислимым типом
Эти базовые свойства должны быть вам знакомы из материалов главы 7
Они четко соответствуют основным функциям Winsock, используемым в примерах клиент-серверных приложений, обсуждавшихся там Некоторые свойства, почти не связанные с API Winsock, для корректного использования элемента управления задавать не следует
Прежде всего необходимо задать свойство Protocol, чтобы указать элемен- ту управления требуемый тип сокета — SOCKJTREAM или SOCK_DGRAM Эле- мент управления действительно создает сокет, и свойство Protocol — един-

4 7 0 ЧАСТЬ II Интерфейс прикладного программирования Winsock ственное, что вы можете изменить Свойство SocketHandle можно считать после установления соединения или после того, как сервер будет связан и переведен в режим ожидания соединений Это полезно, если требуется пе- редать описатель другим функциям API Winsock, импортированным из DLL- библиотеки
С помощью свойства State можно получить информацию о текущем со- стоянии элемента управления Это очень важно, поскольку элемент управ- ления является асинхронным и события могут происходить в любое время
Свойство State позволяет гарантировать, что элемент управления находит- ся в требуемом состоянии для последующих действий Перечислим возмож- ные состояния сокета
Ш sckClosed, значение по умолчанию 0 — сокет закрыт,
sckOpen, значение 1 — сокет открыт,
II sckListening, значение 2 — сокет прослушивает соединения,
sckConnectionPending, значение 3 — поступил запрос на соединение,
но его обработка еще не завершена,
Ш sckResolvingHost, значение 4 — идет разрешение имени компьютера,
sckHostResolved, значение 5 — разрешение имени компьютера завершено,
sckConnecting, значение б — выполнение запроса на соединение нача- то, но не завершено,
Ш sckConnected, значение 7 — соединение завершено,
sckClosing, значение 8 — партнер инициировал закрытие соединения,
sckError, значение 9 — произошла ошибка
Методы
Элемент управления Winsock включает лишь несколько методов За некото- рыми исключениями, большинство имен методов отражают свои эквивален- ты в Winsock Метод для считывания ожидающих данных называется GetData
Обычно он вызывается при наступлении события DataArrtval, извещающе- го о поступлении данных Метод для передачи данных называется SendData
Метод PeekData аналогичен вызову функции Winsock recv с параметром
MSGJPEEK Как обычно, чтение сообщений из памяти отрицательно сказы- вается на производительности, и поэтому его следует избегать всеми воз- можными способами Втабл 15-2 перечислены методы элемента управления
Winsock и их параметры Сами методы более подробно обсуждаются в дру- гих разделах этой главы, посвященных клиент-серверным приложениям
Табл. 15-2. Методы элемента управления Winsock (не возвращают значений)
Метод Параметры Описание
Accept RequestID Только для TCP подключений Используйте метод для приема входящих соединений при обработке события
ConnectionRequest

г
ГЛАВА 15 Элемент управления Winsock
471
Табл. 15-2. (продолжение)
Метод Параметры Описание
Bind
LocalPort
LocallP
Close Нет
Connect RemoteHost
RemotePort
GetData Data
Type
MaxLen
Listen Нет
Peek-
Data
Send-
Data
Data
Type
MaxLen
Data
Связывает сокет с указанным локальным портом и IP-адресом
Используйте метод при наличии нескольких сетевых адапте- ров, вызывая перед методом Listen
Закрывает соединение или прослушивающий сокет
Устанавливает TCP-соединение с заданным портом
(параметр RemotePort) удаленного компьютера (параметр
RemoteHost)
Возвращает ожидающие в настоящий момент данные
Параметры Туре и MaxLen являются необязательными первый определяет тип считываемых данных, второй — ука- зывает количество байт или символов, которое следует счи- тать Для типов данных, отличных от массива байтов и стро- ки, параметры Туре и MaxLen игнорируются
Создает сокет и переводит его в режим прослушивания, ис- пользуется только для ТСР-подключений
Аналогичен методу GetData, но данные не удаляются из системного буфера
Пересылает данные на удаленный компьютер Если передана строка в формате UNICODE, она будет предварительно преоб- разована в формат ANSI Для передачи двоичных данных все- гда используйте тип массив байтов
События
События — это асинхронные процедуры, вызываемые в определенной ситу- ации Для успешного использования элемента управления Winsock приложе- ние на Visual Basic должно уметь обрабатывать различные события, генери- руемые им
Обычно события наступают в результате действий, предпринимаемых партнером Например, частичное закрытие TCP происходит, когда одна из сторон TCP-подключения закрывает сокет Сторона, инициирующая закры- тие, генерирует FIN, а партнер — АСК, чтобы подтвердить запрос на закры- тие На компьютере, принявшем FIN, наступает событие Close Это подсказы- вает Winsock-приложению, что другая сторона больше не передает данные
Затем приложение считывает оставшиеся данные и вызывает со своей сто- роны метод Close, чтобы полностью закрыть соединение В табл 15-3 пере- числены все события Winsock
Табл. 15-3. События элемента управления Winsock
Событие
Аргументы
Наступает
Close
Connect
Нет
Нет
Когда удаленный компьютер закрывает соединение
После успешного вызова метода Connect
см след стр

472
ЧАСТЬ II Интерфейс прикладного программирования Winsock
Табл. 15-3. (продолжение)
Событие
Аргументы
Наступает
Connection-
Request
DataAtrival
Error
SendComplete
SendProgress
RequestID
bytesTotal
Number
Description
Scode
Source
HelpFile
HelpContext
CancelDtsplay
Нет
bytesSent
bytesRemaming
Когда удаленный компьютер передает запрос на установление соединения
При поступлении новых данных
При любых ошибках Winsock
При успешном завершении передачи данных
При передаче данных
Пример (UDP-приложения)
Рассмотрим приложение, использующее протокол UDP. Изучите файл про- екта Visual Basic с именем SockUDP.vbp, записанный в папке Chapterl5 на прилагаемом компакт-диске. После компиляции и запуска проекта на экра- не появится диалоговое окно, аналогичное приведенному на рис. 15-1. Это приложение лишь принимает и передает UDP-сообщения, и потому для об- мена сообщениями можно использовать лишь один его экземпляр.
This is a test Ы the emergency broadcasting
This is a test of the emergency broadcasting
* .I.I.IS^.J!"^! \ \
i
' 6 H SfJi
o r r »
Рис. 15-1. Окно UDP-приложения
На форме имеются два элемента управления Winsock, один из которых принимает, а другой — передает сообщения Кроме того, присутствуют три рамки групп- для отправителя, для получателя и для общей информации
Winsock. В группе получателя следует разместить надписи с именем и IP-ад- ресом принимающего компьютера Задавая свойство RemoteHost, можно ис- пользовать либо текстовое имя машины, либо строковое представление IP- адреса с точечной нотацией. При необходимости элемент разрешит имя.

ГЛАВА 15 Элемент управления Winsock 473
Кроме того, необходим номер удаленного порта, на который вы будете от- сылать UDP-пакеты Обратите также внимание на текстовое поле с номером локального порта — txtSendLocalPort.
Для отправителя важен лишь порт, на который вы передаете данные, ло- кальный порт, через который осуществляется передача, значения не имеет.
Если оставить номер локального порта равным 0, система назначит неис- пользуемый порт.
Последнее текстовое поле — txtSendData, предназначено для пересылае- мых строковых данных На форме также размещаются две командные кноп- ки: одна — для отсылки данных, другая — для закрытия сокета. Для переда- чи дейтаграмм следует связать элемент Winsock с удаленным адресом, уда- ленным портом и локальным портом. Это означает, для изменения любого из этих параметров придется сначала закрыть сокет, а затем связать его с но- выми параметрами. Именно поэтому на форме присутствует кнопка Close
Socket.
В листинге 15-1 приведен код описываемого приложения
Листинг 15-1. Пример UDP-приложения ^
Option Explicit •>
Private Sub cmdExit_Click() (.3
Unload Me ')b«
End Sub "»«4
Private Sub cmdSendOgram_Click() -Д*<-
' Если состояние сокета - "закрыт", нам требуется связать сокет
' с локальным портом, а также с IP-адресом -в>1
1
и портом удаленного компьютера г>оуи M
If (sockSend.State = sckClosed) Then
sockSend.RemoteHost = txtRecipientlP.Text >l*qeO - i/-i
r
sockSend. RemotePort = Clnt(txtSendRemotePor.t.Text) W 3 q e C J0J
r
sockSend.Bind Clnt(txtSendLocalPort.Text)
m ? I?
cmdCloseSend. Enabled = True
a
M f
End If
i ж
lij
' Теперь мы можем передавать данные Г "
1ef
sockSend.SendData txtSendData.Text
End Sub
Private Sub cmdListen_Click()
' Связываем с локальным портом
sockRecv.Bmd Clnt(txtRecvLocalPort.Text)
' Отключаем кнопку, поскольку дважды связать сокет с портом
' было бы ошибкой (для повторной привязки сокет
1
необходимо предварительно закрыть)
см. след. стр

4 7 4 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Листинг 15-1. (продолжение)
cmdListen.Enabled = False
cmdCloseListen.Enabled = True
End Sub
л
Private Sub cmdCloseSend_Click()
}
$
• Закрываем передающий сокет и отключаем кнопку Close ,
sockSend.Close
cradCloseSend.Enabled = False
End Sub
4
''
!
»'
Private Sub cmdCloseUsten_Click() •>•'•
' Закрываем прослушивающий сокет ш
sockRecv. Close og


' Включаем кнопки ? j -yj!
cmdListen. Enabled = True ,тцП Л
cmdCloseListen.Enabled = False
lstRecvData.Clear
End Sub
Private Sub Form_Load()
' Инициализируем протоколы сокета, а также
' задаем некоторые значения и надписи по умолчанию
sockSend. Protocol = sckUDPProtocol i,
sockRecv.Protocol = sckUDPProtocol
h

' tl
lblHostName.Caption = sockSend.LocalHostName
lblLocallP. Caption = sockSend. LocallP
cmdCloseListen.Enabled = False
cmdCloseSend.Enabled = False wjofO
ГI Ш
Timer1.Interval = 500
Timeri.Enabled = True
m
End Sub
Private Sub sockSend_Error(ByVal Number As Integer, _
Description As String, ByVal Scode As Long,
ByVal Source As String, ByVal HelpFile As String, _ >
ByVal HelpContext As Long, CancelDisplay As Boolean)
HsgBox Description
End Sub
Private Sub sockRecv_DataArrival(ByVal bytesTotal As Long)
Dim data As String
' Выделяем строку достаточного размера и получаем данные;

ГЛАВА 15 Элемент управления Winsock
47Б
Листинг 15-1. (продолжение)
' затем добавляем их в описок data = String(bytesTotal + 2, Chr$(O))
sockRecv.GetOata data, , bytesTotal istRecvData.Addltem data
1
Обновляем надписи с удаленным IP-адресом и портом lblRemotelP.Caption = sockRecv.RemoteHostIP
lblRemotePort.Caption = sockRecv.RemotePort
End Sub
Private Sub sockRecv_Error(ByVal Number As Integer,
Description As String, ByVal Scode As Long,
ByVal Source As String, ByVal HelpFile As String,
ByVal HelpContext As Long, CancelDisplay As Boolean)'
HsgBox Description
End Sub
Private Sub Timer1_Timer()
' Когда срабатывает таймер, надписи обновляются ' информацией о состоянии сокета
Hi
Select Case sockSend.State
Case sckClosed lblSenderState.Caption =
Case sckOpen lblSenderState.Caption =
Case sckListening lblSenderState.Caption =
Case sckConnectionPending lblSenderState.Caption =
Case sckResolvingHost lblSenderState.Caption =
Case sckHostResolved lblSenderState.Caption =
Case sckConnecting lblSenderState.Caption =
Case sckClosing lblSenderState.Caption =
Case sckError lblSenderState.Caption =
Case Else lblSenderState.Caption =
End Select
Select Case sockRecv.State
Case sckClosed lblReceiverState.Caption
Case sckOpen lblReceive rState.Caption
'sckClosed"
'sckOpen"
'sckListening"
'sckConnectionPending"
'sckResolvingHost"
'sckHostResolved"
'sckConnecting"
'sckClosing"
'sckError"
"unknown"
= "sckClosed"
= "sckOpen"
см. след. cml

476 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Листинг 15-1. {продолжение) ,Ы Л-
Case sckListening •« « )Sor> : '
lblReceiverState.Caption = "sckListening" •'
Case sckConnectlonPending
lblReceiverState.Caption = "sckConnectionPending"
Case sckResolvingHost
lblReceiverState.Caption = "sckResolvingHost"
Case sckHostResolved
lblReceiverState.Caption = "sckHostResolved"
Case sckConnecting
lblReceiverState.Caption = "sckConnecting"
Case sckClosing
lblReceiverState.Caption = "sckClosing"
Case sckError
lblReceiverState.Caption = "sckError"
Case Else
lblReceiverState.Caption = "unknown"
End Select
End Sub
Пересылка UDP-сообщений
Теперь изучим код программы обмена сообщениями. Обратите внимание на процедуру Form_Load. Сначала требуется задать свойству Protocol элемента управления Winsock sockSend значение sckUDPProtocol. Другие команды в данной процедуре не влияют на функциональность пересылки. Кнопку and-
CloseSend следует отключить для завершенности, поскольку при вызове ме- тода Close для уже отключенного элемента управления ничего не происхо- дит. Заметьте, что элемент управления Winsock по умолчанию закрыт.
Далее мы рассмотрим процедуру cmdSendDgram_Click, которая вызывает- ся щелчком кнопки Send Data. Это основа механизма, отсылающего UDP- сообщения. Прежде всего проверяется состояние сокета. Если сокет закрыт,
его связывают с удаленным адресом, а также с локальным и удаленным пор- тами — состояние элемента управления изменится с sckClosed на sckOpen.
Если код не выполнит эту проверку и будет связывать сокет при каждой пе- редаче данных, произойдет генерация ошибки 40020: Invalid operation at current state. Сокет остается связанным с заданными параметрами до своего закрытия. Именно поэтому код активирует кнопку Close Socket для переда- ющего сокета после привязки элемента управления.
Последний этап — вызов метода SendData и передача ему данных, кото- рые требуется переслать. Когда метод SendData возвращается, это означает,
что код завершил пересылку данных.
С пересылкой UDP-сообщений связаны две другие подпроцедуры. Первая называется cmdCloseSend — она, как и следует из названия, закрывает передаю- щий сокет, позволяя пользователю перед повторной передачей данных изме- нить имя удаленного компьютера, а также номер удаленного или локального порта. Вторая подпроцедура называется sockSend_Error и является событием
Winsock, которое наступает при любой ошибке Winsock. Поскольку протокол

ГЛАВА 15 Элемент управления Winsock 477
I
UDP не надежен, будет генерироваться немного ошибок. В случае ошибки код просто выдает ее описание. Единственное сообщение, выводимое данным приложением, — о недоступности получателя.
Прием UDP-сообщений
Как видите, передавать UDP-пакеты с использованием элемента управления
Winsock просто и удобно. Принимать UDP-пакеты еще легче. Вернемся к процедуре FormLoad. Как и в случае передающего элемента управления
Winsock, код задает свойству Protocol значение UDP, а также отключает кноп- ку Close Listen. Закрытие уже закрытого сокета не создает каких-либо про- блем, однако код все же отключает кнопку для завершенности. Кроме того,
на разных стадиях проектирования приложения вам следует задаваться воп- росом: «Что произойдет, если я вызову метод X?». Источник большинства проблем разработчиков при использовании элемента управления Winsock —
вызов метода при неверном состоянии сокета (например, вызов метода
Connect для уже установившего соединение элемента управления Winsock).
Рассмотрим процедуру cmdListen Click, которая осуществляет прослуши- вание входящих UDP-пакетов. Это обработчик кнопки Listen. Единственное необходимое действие — вызвать метод Bind на принимающем элементе уп- равления Winsock и передать номер локального порта, на котором пользо- ватель хочет прослушивать входящие UDP-дейтаграммы. При прослушива- нии входящих UDP-пакетов коду требуется лишь номер локального порта —
номер удаленного порта, на который пересылаются данные, значения не имеет. После того как код свяжет элемент управления, он отключит кнопку
cmdListen, тем самым предотвращая возможность повторного щелчка кноп- ки Listen пользователем (при попытке связать уже связанный элемент управ- ления произойдет ошибка времени выполнения).
На этом этапе элемент управления sockRecv регистрируется для получения
UDP-данных. Когда на порт, с которым он связан, приходят UDP-данные, на- ступает событие DataArrival, реализованное в процедуре sockRecv JDataArrival.
Значение параметра bytesTotal, который передается событию — число доступ- ных для считывания байт. Код выделяет строку чуть большего размера, чем объем считываемых данных. Затем вызывается метод GetData и вьщеленная строка передается в качестве первого параметра. По умолчанию тип второго параметра — vbString. Третий параметр указывает число байт, которые требу- ется считать, в нашем примере это число определяется значением параметра
bytesTotal. Если код передает запрос на считывание меньшего числа байт, чем значение параметра, генерируется ошибка времени выполнения.
После того как данные считаны и помещены в буфер символов, код до- бавляет их в список считанных сообщений. Затем подпроцедура задает за- головки меток, отображающих IP-адрес и номер порта удаленного компью- тера. При получении любого UDP-пакета свойствам RemoteHostIP и Remote-
Port задаются значения, соответствующие IP-адресу и номеру порта удален- ного компьютера, через который был передан принятый пакет. Таким обра- зом, если приложение получает UDP-пакеты от нескольких компьютеров,
значения этих свойств будут часто изменяться.

4 7 8 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Последние две подпроцедуры, связанные с приемом UDP-сообщений —
cmdCloseListen_Click и sockRecv_Etror. Обработчик cmdCloseListenClick сраба- тывает при щелчке кнопки Close Listen. Процедура лишь вызывает метод
Close для элемента управления Winsock. При закрытии UDP-элемента управ- ления освобождается базовый описатель сокета. Событие sockRecv_Error вы- зывается при любой ошибке Winsock. Как уже упоминалось, из-за неустой- чивой природы будет генерироваться мало ошибок UDP.
Получение информации от элемента Winsock
Последняя часть рассматриваемого примера — рамка группы Winsock Infor- mation. Заголовки меток, содержащих локальное имя и локальный IP-адрес задаются в момент загрузки формы. После загрузки формы и создания эк- земпляров элементов управления Winsock свойствам LocalHostName и LocallP
назначают значения, соответствующие имени и IP-адресу компьютера. Эти значения можно считать в любое время.
Следующие две надписи — Sender State и Receiver State, отображают со- стояние двух используемых приложением элементов управления Winsock.
Сведения о состоянии обновляются два раза в секунду. Здесь в работу вклю- чается элемент управления Timer: каждые 500 миллисекунд он вызывает об- работчик Timer, который запрашивает о состоянии сокетов и обновляет над- писи. Мы выводим сведения о состоянии сокетов для информации. Значе- ния последних двух меток — Remote IP и Remote Port, задают при получении
UDP-сообщения.
Запуск UDP-приложения
Теперь рассмотрим UDP-приложение в работе. Лучший способ протестиро- вать его — запустить экземпляр приложения на трех отдельных компьюте- рах. В одном из приложений щелкните кнопку Listen, а в двух других — вве- дите в поле Recipient's Name/IP имя или IP-адрес компьютера, на котором вы- полняется первый экземпляр. Теперь несколько раз щелкните кнопку Send
Datagram — в соответствующем окне принимающего приложения должны отобразиться сообщения. При приеме каждого сообщения поля группы Win- sock Information обновляются и им задаются значения, соответствующие IP- адресу отправителя и номеру порта, через который было передано сообще- ние. Вы можете воспользоваться командами элемента управления Sender это- го же экземпляра приложения, чтобы принимать сообщения на том же ком- пьютере.
Еще один интересный тест — широковещательная рассылка по опреде- ленной подсети или рассылка широковещательных дейтаграмм. После того как вы отошлете дейтаграмму в определенную подсеть, сообщение получат все прослушивающие приложения (при условии, что все три компьютера тестируются в одной подсети).
Рассмотрим пример: среди тестовых компьютеров имеется две системы с одним сетевым адаптером, их IP-адреса — 157.54.185.186 и 157.54.185.224.
На третьем компьютере установлено несколько сетевых адаптеров; 1Р-адре-

ГЛАВА 15 Элемент управления Winsock 479
са этой системы — 169-254.26.113 и 157.54.185-206. Как видите, все три сис- темы принадлежат к одной подсети — 157.54.185.255.
Давайте на секунду отвлечемся и обсудим одну важную деталь. Для полу- чения UDP-сообщений требуется при вызове метода Bind явно связать эле- мент управления с первым IP-адресом, хранящимся в сетевых привязках.
Этого достаточно, если в системе установлен лишь один сетевой адаптер.
Ну, а если на компьютере несколько сетевых интерфейсов, и следовательно,
несколько IP-адресов? В таком случае второй параметр, передаваемый мето- ду Bind, — IP-адрес, с которым связан элемент управления Winsock. К сожа- лению, свойство элемента управления Winsock возвращает лишь один IP- адрес, методов, позволяющих получить остальные IP-адреса локального ком- пьютера, не существует.
Теперь попробуем осуществить широковещательную рассылку. Закройте все передающие и прослушивающие сокеты во всех запущенных экземпля- рах приложения. На компьютере с одним сетевым адаптером щелкните кноп- ку Listen, чтобы каждая система могла получать сообщения дейтаграмм. Ком- пьютер с несколькими сетевыми адаптерами не используется, поскольку в коде элементы управления не связываются с каким-либо конкретным IP-ад- ресом. На третьем компьютере введите адрес получателя — 157.54.185.255,
и несколько раз щелкните кнопку Send Data. Вы увидите, что сообщение принимают оба приложения.
Вам, возможно, будет интересно, как система выбирает интерфейс для передачи дейтаграммы, если на передающем компьютере установлено не- сколько сетевых адаптеров. Одна из функций таблицы маршрутизации —
определить оптимальный интерфейс для передачи сообщения при наличии конечного адреса и адрес сетевых адаптеров, установленных на локальном компьютере
1
Последний тест таков: закройте передающий сокет на третьем компью- тере, задайте адрес получателя как 255.255.255.255 и несколько раз щелкни- те кнопку Send Datagram. Результаты должны быть одинаковыми: два других прослушивающих приложения получат сообщение. На компьютере с не- сколькими сетевыми адаптерами будет наблюдаться единственное отличие —
UDP-сообщение рассылается по всем сетям, с которыми он соединен.
Состояние UDP-сокетов
Вас, возможно, запутал порядок, в котором должен осуществляться вызов ме- тодов для успешного приема-передачи дейтаграмм. Как упоминалось ранее,
самая распространенная ошибка при программировании элемента управле- ния Winsock — вызов метода, работа которого при текущем состоянии со- кета невозможна. Чтобы избежать таких ошибок, изучите диаграмму на рис. 15-2. Она иллюстрирует состояния сокетов при передаче UDP-сообще-
Подробности о подсетях и маршрутизации см. в литературе, посвященной пакету протоко- лов TCP/IP: например, в книге Ричарда Стивенса «TCP/IP Illustrated Volume I •> (Addison-Wesley.
1994), или доктора Сидни Фейт «TCP/IP Architecture, Protocols, and Implementation with IP v6
and IP Security» (McGraw-Hill. 1996).

480
ЧАСТЬ II Интерфейс прикладного программирования Winsock ний. Обратите внимание, что начальное состояние по умолчанию — sckClosed,
и при указании неверного имени компьютера не генерируется ошибок.
Accept
Bind
Connect
Listen
SendData
GetOata
PeekOata
SendData
GetOata
PeekData
t
Accept Close
Connect
Listen
SendData
GetData
PeekData •«.
Рис. 15-2. Диаграмма состояний UDP-сокета
Пример (TCP-приложение)
Использование элемента управления Winsock с протоколом TCP несколько сложнее, но более распространено, чем с протоколом UDP. Как и в случае
UDP, мы рассмотрим пример ТСР-приложения и подробно изучим его код,
чтобы понять этапы, необходимые для успешного установления ТСР-соеди- нения. На рис. 15-3 изображено запущенное приложение.
186 A message from the local machine'
15754185 224 Another message
15754185 206 Tb»one was sent from a muKihomed machine !$«**. <.„,•
j Local Cbent
1 Local Server
1157 54185 206 157 54185 224 1157 54185186
sckConnected sckListemng sckConnected sckConnected sckConnected
J.DM.
2560 5150 1076 1113 2560
21-
Рис. 15-3. Пример TCP-приложения

ГЛАВА 15 Элемент управления Winsock 481
* В форме на рис. 15-3 три группы флажков: TCP Server, TCP Client и Win- sock Information. Сначала рассмотрим область TCP Server. У сервера есть тек- стовое поле — txtServerPort, для локального порта, к которому сервер будет привязан для прослушивания входящих соединений клиентов. Кроме того на форме имеются две кнопки: одна — для перевода сервера в режим про- слушивания и вторая — для остановки и прекращения приема входящих соединений. Наконец, на рисунке показан единственный элемент Winsock —
sockServer. Если вы взглянете на страницу его свойств, то увидите, что свой- ство Index равно 0 Это значит, что данный элемент фактически является массивом, где может содержаться несколько экземпляров элемента Winsock
Значение 0 указывает, что во время загрузки формы будет создан только один экземпляр (нулевой элемент массива). В любое время можно динами- чески загрузить еще один экземпляр элемента Winsock в массив этого эле- мента.
Массив элементов Winsock — основа серверных возможностей Помни- те, что с одним элементом Winsock связан лишь один описатель сокета. В
главе 7 упоминалось, что когда сервер принимает входящее соединение, для работы с этим соединением создается новый сокет. Наше приложение скон- струировано для динамической загрузки элементов Winsock в ответ на за- прос о соединении от клиента, поэтому соединение можно передать вновь загруженному элементу, не прерывая его обработки сокетом на сервере.
Другой способ — создать х элементов Winsock еще на этапе проектиро- вания. Впрочем, это решение требует значительных ресурсов и плохо мас- штабируется. При старте приложения потребуется много времени, чтобы загрузить все необходимые ресурсы для каждого элемента; кроме того, не всегда ясно, сколько элементов необходимо. Разместив х элементов, вы жест- ко ограничите количество одновременно обслуживаемых клиентов. Если требования вашего приложения допускают фиксирование количества одно- временных соединений, проще реализовать вторую модель, а не массив.
Впрочем, для большинства приложений массив элементов Winsock подой- дет лучше.
В листинге 15-2 приведен код программы. Файл с кодом данного проек- та Visual Basic — SockTCP.vbp, записан в папке Chapter 15 на прилагаемом компакт-диске.
в 1
Листинг 15-2. Пример ТСР-приложения
Option Explicit
1
Индексное значение последнего элемента управления
1
Winsock автоматически загружается в массив sockServer
Private Serverlndex As Long
Private Sub cmdCloseListen_Click()
Dim itemx As Object
' Закрываем прослушивающий сокет сервера. После этого клиенты
• не смогут подключаться к серверу
см. след. стр.

482 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Листинг 15-2. (продолжение)
sockServer(O).Close cmdListen.Enabled = True cmdCloseListen.Enabled = False
Set itemx = lstStates.Listltems.ltem(2)
itemx.SubItems(2) = "-1"
End Sub
Private Sub cmdConnect_Click()
1
Заставляем клиентский элемент управления попытаться ' подключиться к заданному серверу ' по указанному номеру порта sockClient.LocalPort = 0
sockClient.RemoteHost = txtServerName.Text sockClient.RemotePort = Clnt(txtPort.Text)
sockClient.Connect cmdConnect.Enabled = False
End Sub
Private Sub cmdDisconnect_Click()
Dim itemx As Object
' Закрываем клиентское подключение и настраиваем ' командные кнопки для последующих соединений sockClient.Close cmdConnect.Enabled = True cmdSendData.Enabled = False cmdDisconnect. Enabled = False
' Задаем номер порта как -1, чтобы указать отсутствие соединения
.эй,
Set itemx = lstStates.Listltems.Item(i)
itemx.Subltems(2) = "-1"
И
End Sub
yA
Private Sub cmdExit Click()
Unload He " ^ •
|a
*
J
*>
End Sub
Private Sub cmdListen_Click()
V
'
Dim itemx As Object *
' Переводим серверный элемент управления в режим прослушивания
' на порту с заданным номером sockServer(O).LocalPort = Clnt(txtServerPort.Text)
sockServer(O).Listen
Set itemx = lstStates.Listltems.Item(2)

1   ...   35   36   37   38   39   40   41   42   ...   50


написать администратору сайта