Программирование в сетях Windows
.pdf478 |
ЧАСТЬ II Интерфейс прикладного программирования Winsock |
Последние две подпроцедуры, связанные с приемом UDP-сообщений — cmdCloseListen_Click и sockRecv_Etror. Обработчик cmdCloseListenClick срабатывает при щелчке кнопки Close Listen. Процедура лишь вызывает метод Close для элемента управления Winsock. При закрытии UDP-элемента управления освобождается базовый описатель сокета. Событие sockRecv_Error вызывается при любой ошибке Winsock. Как уже упоминалось, из-за неустойчивой природы будет генерироваться мало ошибок UDP.
ПолучениеинформацииотэлементаWinsock
Последняя часть рассматриваемого примера — рамка группы Winsock Information. Заголовки меток, содержащих локальное имя и локальный 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 — в соответствующем окне принимающего приложения должны отобразиться сообщения. При приеме каждого сообщения поля группы Winsock Information обновляются и им задаются значения, соответствующие IPадресу отправителя и номеру порта, через который было передано сообщение. Вы можете воспользоваться командами элемента управления Sender этого же экземпляра приложения, чтобы принимать сообщения на том же компьютере.
Еще один интересный тест — широковещательная рассылка по определенной подсети или рассылка широковещательных дейтаграмм. После того как вы отошлете дейтаграмму в определенную подсеть, сообщение получат все прослушивающие приложения (при условии, что все три компьютера тестируются в одной подсети).
Рассмотрим пример: среди тестовых компьютеров имеется две системы с одним сетевым адаптером, их IP-адреса — 157.54.185.186 и 157.54.185.224. На третьем компьютере установлено несколько сетевых адаптеров; 1Р-адре-
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 |
" |
|
|
End |
Sub |
|
|
|
Private Sub cmdListen_Click() |
|
|||
|
Dim itemx As |
Object |
|
|
|
' |
Переводим |
серверный элемент управления в режим прослушивания |
|
|
' |
на порту с заданным номером |
|
|
|
sockServer(O).LocalPort = Clnt(txtServerPort.Text) |
|
||
|
sockServer(O).Listen |
|
||
|
Set itemx = |
lstStates.Listltems.Item(2) |
|
484 |
ЧАСТЬ II |
Интерфейс прикл |да>Г»1№Щ»ИИЦ10ванияМп«оок |
||||||
|
|
|
|
|
|
|||
Листинг 15-2. (продолжение) |
(щ, |
щ |
,£.ЗГ |
|||||
|
TimeM.Interval |
= |
500 |
io4feDOJ.(*)tevi |
|
П е в д Ш и * |
||
|
Timeri.Enabled |
= |
True |
|
|
|
|
|
End Sub |
|
|
|
soi"" |
ьШ |
|||
Private Sub sockClient_Close() |
|
|
|
|
||||
|
sockClient. Close |
|
|
|
|
|
||
End Sub |
|
|
|д f |
|
|
|
|
Private Sub sockClient_Connect()
Dim itemx As Object
' Соединение было успешным, активируем кнопки передачи данных
cmdSendData.Enabled = True cmdDisconnect.Enabled = True
Set itemx = lstStates.Listltems.Item(i) itemx.Subltems(2) = sockClient.LocalPort
End Sub
Private Sub sockClient_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)
'У элемента управления Client произошла ошибка: выводим
'сообщение и закрываем элемент управления. Ошибка переводит
|
' |
элемент управления в |
состояние sckError; |
переход в другое состояние |
||||
|
' |
возможен после вызова |
метода |
Close. |
|
|
||
|
MsgBox Description |
|
|
|
|
|||
|
sockClient.Close |
|
|
|
|
|||
|
cmdConnect.Enabled = True |
|
|
|
||||
End |
Sub |
|
|
|
|
|
|
|
Private Sub sockServer_Close(index As Integer) |
|
|
||||||
|
Dim |
itemx |
As Object |
|
|
|
|
|
|
1 |
Закрываем данный элемент управления Winsock |
,j_ |
|||||
|
sockServer(index).Close |
|
|
|
aej |
|||
|
Set itemx = lstStates.Listltems.ltem(index + 2) |
|
||||||
|
lstStates.Listltems.ltem(index + 2).Text = "-.-.-.-" |
|
||||||
|
itemx.Subltems(2) = "-1" |
|
|
|
||||
End |
Sub |
|
|
|
|
|
|
|
Private |
Sub sockServer_ConnectlonRequest(lndex As Integer, _ |
|
||||||
|
|
|
ByVal |
requestID As |
Long) |
|
|
|
|
Dim |
i As |
Long, place As |
Long, |
freeSock As |
Long, itemx As |
Object |
486 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Листинг 15-2. |
{продолжение) |
|
|
|
|
|
|
|
|
|
<'*«' |
||||||
data = String(bytesTotal + 2, |
|
Chr$(0)) |
|
|
|
|
|
|
|
|
|
||||||
sockServer(index).GetData |
data, |
vbString, bytesTotileN0>-'eM |
**fcG»«!rw«ooqn |
||||||||||||||
1 |
Добавляем |
IP-адрес |
клиента |
в |
начало сообщения |
оичогшоН |
<<нжои |
йш}ото» |
|||||||||
' |
и помещаем сообщение в список |
|
|
|
|
|
0 |
? Яз<3ав'1 |
|||||||||
|
|
|
|
|
|
|
|
|
|
|
XebflIi8V4«8 ОТ |
t |
» |
t ifi |
|||
entry = sockServer(index).RemoteHostIP & |
": " |
& |
йШР-ИР^чШа™ |
tl |
• |
||||||||||||
lstMessages.Addltem |
entry |
|
|
|
|
|
|
I |
* |
Jte |
|
* |
^ |
||||
End Sub |
|
|
|
|
|
|
|
|
|
|
K ' |
|
J |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
", ел |
|
|
Private Sub sockServer_Error(index As Integer, |
_ |
|
|
|
|
|
|
I |
|||||||||
|
ByVal |
Number As |
Integer, |
Description |
As |
String, |
_ |
|
|
|
|
f« |
|||||
|
ByVal |
Scode As |
Long, |
ByVal |
Source As |
String, |
_ |
|
|
|
|
|
|
||||
|
ByVal |
HelpFile |
As String, |
|
ByVal HelpContext |
As |
Long, |
_ |
|
|
- |
»«8вм |
|||||
|
CancelDisplay |
As |
Boolean) |
|
|
|
|
|
|
|
|
|
|
||||
' |
Выводим |
сообщение |
об ошибке |
и закрываем |
указанный элемент |
Аоо&тчЧ |
'управления. Ошибка переводит элемент управления в состояниеifi
'sckError, которое снимается лишь после вызова метода Close. Ьое
MsgBox Description |
|
|
|
|
|
|
|
|
' |
|||
sockServer(index).Close |
|
|
|
|
|
|
|
»' |
saetq |
|||
End Sub |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
a |
|
|
Private Sub Timer1_Timer() |
|
|
|
|
|
|
|
|
|
|||
Dim |
i As |
Long, index As Long, |
itemx As |
Object |
|
|
|
|
bf?3 |
|||
|
|
|
|
|
|
|
|
|
|
|
3 ' |
|
' |
Задаем |
состояние локального |
элемента |
управления |
Winsock клиента |
-я |
|
|||||
|
|
|
|
|
|
|
|
|
|
|
а ' |
|
Set |
itemx |
= |
lstStates.Listltems.Item(i) |
|
|
|
|
|
4 |
|||
Select Case |
sockClient.State |
|
|
|
|
|
|
*» |
>oo |
|||
|
Case |
sckClosed |
|
|
|
|
|
|
|
|
|
|
|
itemx.Subltems(i) |
= |
"sckClosed" |
|
|
|
»'«**т <* |
'»••">* |
U |
|||
|
Case |
sckOpen |
|
|
|
|
»5 |
ee)a?2JaI |
• |
, je8 |
||
|
itemx.Subltemsd) |
= |
"sckOpen" |
•" |
|
levied |
lev1* |
ч |
|
|||
|
Case |
sckListening |
|
|
|
|
|
|
|
|
|
|
|
itemx.Subltems(1) |
= |
"sckListening" |
|
•»?*/??ei |
*• |
/ Je8 |
|
||||
|
Case |
sckConnectionPending |
|
r1r |
(»»I*JIJ9I. |
'Stel |
|
|||||
|
itemx.Subltems(1) |
= |
"sckConnectionPending" |
"itjiev |
•» |
|
|
|||||
|
Case |
sckResolvingHost |
|
|
|
|
|
|
|
|
tl |
|
|
itemx. Subltems(1) |
= |
"sckResolvingHost" |
|
e e <£)«t«iejJd«3.xt»s3f |
|
||||||
|
Case |
sckHostResolved |
|
|
|
|
|
|
|
|
|
|
|
itemx.Subltemsd) |
= |
"sckHostResolved" |
|
|
|
|
ЙУЗ bn- |
||||
|
Case |
sckConnecting |
|
|
|
|
|
|
|
|
|
|
|
itemx.Subltems(1) |
= |
"sckConnecting" |
|
ftO.iwn |
t <J«8 eJeviTl |
||||||
|
Case |
sckConnected |
|
|
|
|
|
|
»" 1' |
|
'л\' |
|
|
itemx. Subltemsd) |
= |
"sckConnected" |
|
lf! |
|
' 1 |
• |
||||
|
Case |
sckClosing |
|
|
|
|
|
|
|
|
|
|
|
itemx.Subltems(1) |
= |
"sckClosing" |
|
|
|
>f" |
|
||||
|
Case |
sckError |
|
|
|
|
|
|
|
|
|
|
|
itemx.Subltemsd) = "sckError" |
|
|
|
|
|
|
|
|
|
|
|
ГЛАВА 15 Элемент управления Winsock |
487 |
|
Листинг 15-2. |
(продолжение) |
|
|
|
|||
|
Case Else |
|
|
|
|
|
|
|
|
itemx.Subltems(i) = "unknown: " & sockClient.State |
|
||||
End Select |
|
|
|
|
|
||
|
Теперь |
задаем |
состояния прослушивающего серверного элемента |
|
|||
' |
управления, а также элементов |
управления всех подсоединенных |
|
||||
1 |
клиентов |
|
|
|
|
|
|
index = |
О |
|
|
|
|
|
|
For i = 2 To Serverlndex + 2 |
|
|
|
||||
*Й |
Set |
itemx |
= |
lstStates.Listltems.Item(i) |
|
||
|
|
|
|
|
|
|
|
Г |
Select Case |
sockServer(index).State |
|
||||
|
|
||||||
|
|
Case |
sckClosed |
|
|
|
|
|
|
ltemx.Subltems(i) |
= |
"sckClosed" |
|
||
|
|
Case |
sckOpen |
|
|
|
|
|
|
ltemx.Subltems(i) = |
"sckOpen" |
|
|||
|
|
Case |
sckListening |
|
|
|
|
|
|
ltemx.Subltems(i) |
= |
"sckListening" |
|
||
|
|
Case |
sckConnectionPending |
|
|||
|
|
itemx.Subltemsd) = |
"sckConnectionPending" |
|
|||
|
|
Case |
sckResolvingHost |
|
|
|
|
|
|
itemx.Subltems(1) |
= |
"sckResolvingHost" |
|
||
|
|
Case |
sckHostResolved |
|
|
|
|
|
|
itemx.Subltemsd) = "sckHostResolved" |
|
||||
|
|
Case |
sckConnecting |
|
|
|
|
|
|
itemx.Subltems(1) |
= |
"sckConnecting" |
|
||
|
|
Case |
sckConnected |
|
|
|
|
|
|
itemx.Subltems(1) |
= |
"sckConnected" |
|
||
|
|
Case |
sckClosing |
|
|
|
|
|
|
itemx.Subltems(1) |
= |
"sckClosing" |
|
||
|
|
Case |
sckError |
|
|
|
|
|
|
itemx.Subltemsd) = "sckError" |
|
||||
|
|
Case |
Else |
|
|
|
|
|
|
itemx.Subltemsd) = "unknown" |
|
||||
|
End |
Select |
|
|
|
|
|
|
index = index + 1 |
|
|
|
|||
Next i |
|
|
|
|
|
|
|
End Sub |
|
|
|
|
|
|
ТСР-сервер
Рассмотрим код формы. Обратите внимание на процедуру Form Load из листинга 15-2. Два первых параметра лишь присваивают надписям значения, соответствующие имени и IP-адресу локального компьютера. Эти надписи находятся в рамке группы Winsock Information, которая служит тем же целям, что и информационная группа из примера с UDP. Далее серверный элемент управления sockServer инициализируется с параметром sckTCPProtocol. Нулевой элемент массива элементов управления Winsock всегда является