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

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


Скачать 2.88 Mb.
НазваниеЭ. Джонс, Д. Оланд
АнкорПрограммирование в сетях Windows.pdf
Дата12.10.2017
Размер2.88 Mb.
Формат файлаpdf
Имя файлаПрограммирование в сетях Windows.pdf
ТипКнига
#9346
страница40 из 50
1   ...   36   37   38   39   40   41   42   43   ...   50
ГЛАВА 16 Элемент управленийWinsock
483
Ie\
Листинг 15-2. (продолжение)
itemx.Subltems(2) = sockServer(0).LocalPort cmdCloseListen.Enabled = True cmdListen.Enabled = False
End Sub
Private Sub cmdSendData_Click()
' При наличии соединения передаем указанные данные на сервер
If (sockClient.State = sckConnected) Then
sockClient.SendData txtSendData.Text
Else
MsgBox "Unexpected errorl Connection closed"
Call cmdDisconnect_Click
End If
End Sub
.f
008
uut
Q f A
Private Sub Form_Load()
Dim itemx As Object
lblLocalHostname.Caption = sockServer(0).LocalHostName
lblLocalHostlP.Caption = sockServer(O).LocallP
' Инициализируем свойство Protocol со значением sckTCPProtocol,
' мы будем использовать только протокол TCP
Serverlndex = 0
sockServer(O). Protocol = sckTCPProtocol
sockClient.Protocol = sckTCPProtocol
' Настраиваем кнопки '
cmdDisconnect. Enabled = False „ W I T * «„a»n.
cmdSendData.Enabled = False *?
cmdCloseListen.Enabled = False
' Инициализируем элемент управления ListView, содержащий
' информацию о текущем состоянии всех созданных элементов
' управления Winsock (необязательно подключенных или используемых)
Set itemx = lstStates.ListItems.Add(1, , "Local Client")
itemx. Subltemsd) = "sckClosed"
itemx.Subltems(2) = "-1"
Set itemx = lstStates.ListItems.Add(2, , "Local Server")
itemx.Subltems(1) = "sckClosed"
itemx.Subltems(2) = "-1"
' Инициализируем таймер, который управляет скоростью
' обновления информации об упоминавшихся выше состояниях сокетов
. У Л ' *r,i1s. лей
duS ЬлЗ
!
'Y
fi
даясмсоа
d u S
си. след. стр.

4 8 4 ЧАСТЬ 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

ГЛАВА 15 Элемент управления Wmsock
485
Листинг 15-2. {продолжение)
' Просматриваем массив и ищем закрытый элемент управления,
1
который можно повторно использовать
freeSock = О
For i = 1 То Serverlndex
If sockServer(i).State = sckClosed Then
freeSock = l j&
Exit For
End If
Next l ,
0?
' Если значение freeSock по-прежнему равно 0, свободные элементы [
' управления отсутствутют, и поэтому мы загружаем
£
1
новый элемент управления Winsock - г
If freeSock = 0 Then
Serverlndex = Serverlndex + 1
Load sockServer(Serverlndex)
sockServer(Serverlndex).Accept requestID
place = Serverlndex
Else
sockServer(f reeSock).Accept requestID
place = freeSock
End If
' Если не было обнаружено свободных элементов управления,
' выше мы добавляем дополнительный элемент. Создайте
' в элементе управления ListView запись для нового элемента
' управления. В любом случае установите состояние нового
' соединения как sckConnected.
If freeSock = 0 Then
Set itemx = lstStates.ListItems.Add(, ,
sockServer(Serverlndex).RemoteHostlP)
Else
Set itemx = lstStates.ListItems.Item(freeSock + 2)
lstStates.ListItems.Item(freeSock + 2).Text = _
sockServer(freeSock).RemoteHostIP
End If
itemx.Subltems(2) = sockServer(place).RemotePort
End Sub
Private Sub sockServer_DataArrival(mdex As Integer,
ByVal bytesTotal As Long)
Dim data As String, entry As String
' Выделяем строковый буфер достаточного размера и получаем данные
due
чмв(\»всгу
«eC
due bnd
.IT
J
I
Ю
см след стр

4 8 6 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Листинг 15-2. {продолжение) <'*«'
data = String(bytesTotal + 2, Chr$(0))
sockServer(index).GetData data, vbString, bytesTotil eN0>
-'
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() J
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 lev
1
* ч
Case sckListening « 1 3
itemx.Subltems(1) = "sckListening" •»?*/??ei *• / Je8
Case sckConnectionPending
r1r
(»»I*JIJ9I.
'Stel
itemx.Subltems(1) = "sckConnectionPending" "itjiev •»
Case sckResolvingHost tl nirt
itemx. Subltems(1) = "sckResolvingHost"
e e
<£)«t«iejJd«3.xt»s3f
Case sckHostResolved
itemx.Subltemsd) = "sckHostResolved"
ЙУЗ bn-J
Case sckConnecting
itemx.Subltems(1) = "sckConnecting" ftO.iwn t
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 всегда является

488 ЧАСТЬ II Интерфейс прикладного программирования Winsock прослушивающим сокетом Затем процедура отключает кнопку Close Listen,
которая активируется, лишь когда сервер снова начнет прослушивать кли- ентские соединения
Последняя часть процедуры настраивает элемент управления LtstView с именем istStates Он отображает состояние каждого используемого в настоя- щий момент элемента управления Winsock Код добавляет записи для кли- ентского и серверного элемента управления, и они становятся элементами 1
и 2, соответственно Все прочие динамически загружаемые элементы управ- ления Winsock добавляются после этих двух записей Имя записи о сервер- ном элементе управления — Local Server Как и в примере с протоколом UDP,
процедура настраивает таймер для управления частотой обновления состо- яний сокетов По умолчанию триггеры таймеров обновляются каждые пол- секунды
Теперь давайте рассмотрим две кнопки, используемые сервером Первая —
Listen, инициирует несложное действие Обработчик этой кнопки — cmdListen,
задает свойству значение, введенное пользователем в поле txtServerPort Поле с номером локального порта наиболее важно для прослушивающего сокета
Именно к порту с этим номером клиенты пытаются подключиться, чтобы ус- тановить соединение Задав свойство LocalPort, код вызывает метод Listen Как только обработчик кнопки Listen переведет элемент управления sockServer в прослушивающее состояние, программа начнет ожидать, когда для элемента управления sockServer наступит событие ConnectionRequest, указывающее, что клиент пытается установить соединение Кнопка Close Listen закрывает элемент управления sockServer Обработчик кнопки Close Listen вызывает метод Close для элемента sockServer(0), запрещая установление соединений клиентами
Наиболее важное событие для TCP-сервера — ConnectionRequest, оно об- рабатывает входящие запросы клиентов Поступивший от клиента запрос на соединение можно обработать двумя способами Первый — воспользовать- ся непосредственно сокетом сервера Вызовите метод Accept для элемента уп- равления сервера с параметром requestID, который передается обработчику события — это пример действий SockTCP Недостаток данного метода — про- слушивающий сокет будет закрыт и другие клиенты не смогут установить со- единение с сервером
Помните, что нулевой элемент массива элементов управления Winsock является прослушивающим сокетом Прежде всего просмотрите массив и найдите элемент управления с состоянием «закрыт» (например, в запросе укажите, что значение свойства State должно равняться sckClosed) Конечно,
на первом этапе вы не обнаружите свободных элементов управления, по- скольку они вообще не загружены В этом случае первый цикл не выполня- ется и значение переменной freeSock будет по-прежнему равно О, сообщая,
что свободные элементы управления не обнаружены Следующие этапы ди- намически загружают новый элемент управления Winsock, увеличивая зна- чение счетчика Serverlndex (место в массиве, куда следует загрузить элемент управления), и затем выполняют следующий оператор
Load sockServer(Serverlndex)

Г Л А В А 15 Элемент управления Winsock 489
Теперь, когда новый элемент Winsock загружен, процедура может вызвать
метоц Accept с указанным идентификатором запроса (request ID) Оставшие- ся операторы добавляют новую запись в элемент управления ListView с име- нем IstStates, чтобы приложение могло отображать текущее состояние нового элемента управления Winsock
Если состояние уже загруженного элемента Winsock — «закрыт>, проце- дура повторно воспользуется данным элементом управления, вызвав для него метод Accept Непрерывная загрузка и выгрузка элементов управления занимает много процессорного времени и снижает производительность
Кроме того, при выгрузке элемента управления Winsock может возникнуть утечка памяти (подробней — далее в этой главе)
Оставшиеся серверные функции просты Событие sockServer_Close насту- пает, когда клиент вызывает метод Close Тогда сервер закрывает со своей сто- роны сокет и обнуляет запись об IP-адресе в элементе управления ListView,
присваивая ей значение «- •> и задавая номер порта как -1 Функция
sockServer_DataAmval выделяет буфер для приема данных, а затем вызывает метод GetData для считывания информации В результате в список IstMessages
добавляется сообщение Последняя серверная функция — обработчик собы- тия Error При ошибке обработчик выводит соответствующее сообщение и закрывает элемент управления
ТСР-клиент
Теперь рассмотрим код клиентской части Единственная инициализация, вы- полняемая клиентом в процедуре Form_Load, — выбор протокола TCP для элемента управления sockdient He входящие в код инициализации три об- работчика командных кнопок связаны с клиентом и некоторыми обработ- чиками событий Первая кнопка — Connect, ее обработчику — cmdConnect_Chck
LocalPort, задано значение 0, поскольку номер порта, выбранного на локаль- ном компьютере, не важен Параметры RemoteHost и RemotePort задаются в соответствии со значениями полей txtServerName и txtPort Это вся инфор- мация, необходимая для установки TCP-соединения с сервером
Единственное, что осталось сделать — вызвать метод Connect После этого элемент управления Winsock будет находиться в процессе разрешения имени или установки соединения (состояние элемента управления — sckResolvingHost,
sckResolved ъиы sckConnectmg) Когда соединение установлено, состояние изме- няется на sckConnected и наступает событие Connect Далее рассматриваются различные состояния элемента управления и переходы между ними
После установления соединения вызывается обработчик sockChent_Connect,
который активирует кнопки Send Data и Disconnect Кроме того, для записи
Local Client в элементе управления ListView с именем IstStates будет обновлен номер порта локального компьютера, через который устанавливается соедине- ние Теперь вы можете принимать и передавать данные
Существуют и два других обработчика событий sockChent Close и sock-
Chent_Error Обработчик события sockChent_Close лишь закрывает элемент управления Winsock, а обработчик события sockChent JLrror — выводит окно сообщения с описанием ошибки и затем закрывает элемент управления

4 9 0 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Две оставшихся части кода клиента — командные кнопки Send Data и
Disconnect. Кнопку Send Data обрабатывает подпроцедура cmdSendData_
Click. Если состояние элемента управления Winsock — «подключен», проце- дура вызывает метод SendData, передавая ему строку из поля txtSendData.
Кнопку Disconnect обрабатывает подпроцедура cmdDisconnect_Click. Данный обработчик лишь закрывает клиентский элемент управления, возвращает не- которые кнопки в исходное состояние, а также обновляет запись Local Client в элементе управления istStates.
Получение информации о состоянии элемента
управления Winsock
Последняя часть примера, использующего протокол TCP, — рамка группы
Winsock Information. Мы уже обсуждали подобную рамку, однако для яснос- ти вкратце рассмотрим ее повторно.
Как и в примере с UDP, таймер управляет обновлением информации о текущем состоянии всех загруженных элементов управления Winsock. Пери- одичность обновления по умолчанию — 500 миллисекунд. При загрузке в элемент управления Listview с именем IstStates добавляются две записи. Пер- вая — надпись Local Client, соответствующая клиентскому элементу управ- ления Winsock sockClient. Вторая — Local Server, относится к прослушиваю- щему сокету. При установлении нового клиентского соединения динамичес- ки загружается новый элемент управления Winsock и в элемент управления
sckStates добавляется новая запись — IP-адрес клиента. После отключения клиента запись возвращается в исходное состояние — IP-адрес «—.—.—.—»,
номер порта — (-1). Конечно, подключающийся новый клиент повторно использует неиспользуемые элементы из серверного массива. Так же отобра- жаются IP-адрес и имя локального компьютера.
Запуск ТСР-приложения
Запуск ТСР-приложения не вызывает каких-либо трудностей. Запустите по экземпляру приложения на трех отдельных компьютерах. При использова- нии TCP не имеет значения, сколько сетевых адаптеров установлено на ком- пьютерах, поскольку оптимальный интерфейс для данного ТСР-соединения выбирает таблица маршрутизации. В одном из приложений щелкните кноп- ку Listen. Вы увидите, что значение записи Local Server в элементе управле- ния ListView с именем State Information изменилось с sckClosed на sckListening,
а номер порта задан как 5150. Теперь сервер может принимать клиентские запросы на соединение.
На одном из клиентов задайте полю Server Name значение, соответствую- щее имени компьютера, на котором выполняется первый экземпляр прило- жения (прослушивающий сервер) и затем щелкните кнопку Connect. Эле- мент управления, которому в клиентском приложении соответствует запись
Local Client из списка State Information, теперь находится в состоянии sck-
Connected, а в качестве номера порта, через который установлено соедине- ние, отображается неотрицательное число. Кроме того, на сервере в список

Г Л А В А 15 Элемент управления Winsock 491
State Information добавляется запись — IP-адрес только что подключившего- ся клиента. Состояние новой записи — sckConnected, она также содержит но- мер порта сервера, с которым установлено соединение.
Теперь введите текст в поле Message клиентского приложения и несколь- ко раз щелкните кнопку Send Data. Вы увидите сообщения, появляющиеся в окне списка Messages серверного приложения. После этого отключите кли- ент, щелкнув кнопку Disconnect. На клиентском компьютере записи Local
Client из списка State Information будет назначено состояние sckClosed, a номер порта задан как — 1. На сервере запись, соответствующая клиенту, не удаляется, а лишь помечается как неиспользуемая. Ее имя задается, как IP-ад- рес «—.—.---.—», номер порта — как -1 и состояние — как sckClosed.
На третьем компьютере введите в поле Server Name имя прослушивающе- го сервера и установите клиентское подключение. Вы получите те же резуль- таты, что и в случае с первым клиентом, но для обработки второго клиента сервер будет использовать тот же элемент управления Winsock. Если состо- яние элемента Winsock — «закрыт», он может применяться для принятия лю- бых входящих соединений. Последнее, что мы советуем сделать, — исполь- зуйте клиент на стороне сервера, чтобы установить соединение локально.
После того, как соединение будет установлено, в список Socket Information добавится новая запись. Единственное отличие в том, что теперь указан IP- адрес, соответствующий IP-адресу сервера. Поработайте с клиентскими и серверными приложениями, чтобы понять, как они взаимодействуют и ка- кие результаты дает выполнение каждой из команд.
Состояние ТСР-сокетов
Использовать элемент управления Winsock с протоколом TCP значительно сложнее, чем работать с UDP-сокетами, поскольку здесь гораздо больше стояний сокетов. На рис. 15-4 приведена диаграмма состояний ТСР-сокета.
Начальное состояние по умолчанию — sckClosed. Переходы между состояни- ями просты и не требуют каких-либо комментариев, за исключением состо- яния sckClosing.
Из-за частичного закрытия TCP метод SendData может перейти из этого состояния в другое двумя способами. Как только одна из сторон ТСР-соеди- нения вызовет метод Close, она больше не сможет передавать данные. Дру- гая сторона соединения получает событие Close и переходит в состояние
sckClosing, но по-прежнему может передавать информацию. Именно поэто- му для метода SendData существует два пути перехода из состояния sck-
Closing. Если сторона, вызвавшая метод Close, пытается вызвать SendData, ге- нерируется ошибка и состояние элемента управления Winsock изменяется на sckError. Сторона, получившая событие Close, может свободно передавать информацию и принять все оставшиеся данные.
Ограничения
Элемент управления Winsock действительно удобен и прост в использова- нии, но к сожалению, несколько ошибок делают его непригодным для кри-

492
ЧАСТЬ II Интерфейс прикладного программирования Winsock тичных приложений Эти ошибки имеются в последней версии Winsock для
Visual Basic 5.0, которая представляет собой новую версию элемента управ- ления из второго пакета обновлений.
- Close
Close
Accept
Bind
Connect
Listen
SendData
GetData
PeekData
Рис. 15-4. Диаграмма состояний ТСР-сокета
Первая ошибка не значительна и связана с загрузкой и выгрузкой Win- sock. При выгрузке ранее загруженного элемента управления происходит утечка памяти. В связи с этим в нашем примере мы не загружаем и не вы- гружаем элемент управления, когда клиент устанавливает соединение и от- ключается. После загрузки элемента Winsock в память мы сохраняем его для использования другими клиентами.
Вторая ошибка связана с закрытием сокетного соединения, до того как в сеть будут переданы все запрошенные данные. В некоторых случаях при вызове метода Close после события SendData (когда Close обрабатывается раньше SendData) имеет место потеря данных, по крайней мере, с точки зре- ния получателя. Чтобы обойти эту проблему, перехватывайте событие Send-
Complete (оно наступает, после того как метод SendData завершит передачу данных в сеть). Кроме того, транзакции приема-передачи можно организо- вать так, чтобы получатель, приняв все ожидаемые данные, вызывал метод
Close первым. В результате на принимающем компьютере наступит событие
Close, извещающее, что все данные получены и соединение можно закрыть.
Последняя и наиболее серьезная ошибка — потеря данных, когда на пе- редачу отправляется буфер большого размера. Если в очередь для передачи по сети поставлен достаточно большой блок данных, внутренний буфер эле- мента управления переполняется и некоторая информация теряется. К со- жалению, полного решения этой проблемы нет. Наилучший способ — пере-

Г Л А В А 15 Элемент управления Winsock 493
давать данные блоками, размер которых не превышает 1000 байт. Передав буфер, подождите, пока наступит событие SendComplete, прежде чем пере- дать следующий буфер с данными. Это неудобно, но значительно повышает надежность элемента управления.
В новейшей версии Winsock, поставляемой с Visual Basic 6.0, исправлены все упомянутые ошибки, за исключением второй. Если вызвать команду Close
после вызова метода SendData, сокет немедленно закроется, не передав ка- кие-либо данные. Было бы просто здорово, если бы программисты Microsoft исправили и эту ошибку, хотя она наименее серьезная и сложная.
Типичные ошибки
Как мы уже не раз говорили, в процессе работы приложение может столк- нуться с достаточно ограниченным числом ошибок Winsock. Мы не будем рассматривать их все, а обсудим лишь наиболее распространенные: Local address in use (Локальный адрес уже используется) и Invalid operation at current state (Неверное действие в текущем состоянии).
Ошибка Local address in use
Эта ошибка наступает, если связать элемент управления с локальным портом при помощи методов Bind или Connect, при том что порт уже используется.
Это наиболее распространенная ошибка TCP-сервера, который всегда свя- зывается с конкретным портом, чтобы клиенты могли обнаружить службу.
Если перед завершением работы приложения, использующего сокет, по- следний не будет должным образом закрыт, он на короткий период време- ни перейдет в состояние TIME_WAIT, чтобы гарантировать, что через этот порт отправлены (переданы) все данные. При попытке связать другой эле- мент Winsock с этим портом генерируется ошибка Local address in use.
Распространенная ошибка на стороне клиента приводит к такой же си- туации. Если свойству LocalPort задается значение 0 и затем устанавливает- ся соединение, свойству LocalPort задается значение, соответствующее номе- ру локального порта, через который клиент установил соединение. Если вы собираетесь в дальнейшем установить новое соединение, используя данный элемент управления, не забудьте вернуть свойству LocalPort значение 0. В
противном случае, если предыдущее соединение не будет корректно закры- то, возможна ошибка Local address in use.
Ошибка Invalid Operation at Current State
Эта ошибка также широко распространена и возникает, если вызвать метод элемента управления Winsock, выполнение которого не допускается теку- щим состоянием элемента. На рис. 15-2 и 15-4 приведены диаграммы состо- яний UDP- и ТСР-сокетов. Для создания устойчивого кода всегда проверяй- те состояние сокета, прежде чем вызвать какой-либо метод.
Ошибки Winsock генерируются в результате наступления события Error.
Это те же ошибки, что возникают при прямом программировании Winsock.

4 9 4 ЧАСТЬ II Интерфейс прикладного программирования Winsock
Подробное описание ошибок Winsock см. в главе 7 или в приложении С, где перечислены коды.
Элемент управления Windows CE Winsock
В комплекте инструментов Visual Basic Toolkit for Windows CE (VBCE) име- ется элемент управления Winsock, предоставляющий большинство функций
«стандартного» элемента управления Winsock, поставляемого с Visual Basic.
Основное его отличие — протокол UDP не поддерживается, но обеспечива- ется поддержка протокола IrDA. Кроме того, требуются некоторые незначи- тельные изменения в коде приложения.
Как упоминалось в главе 7, Windows CE не поддерживает асинхронную модель Winsock, и элемент управления Windows CE Winsock не исключение из этого правила. Главное различие при программировании — метод Connect
является блокирующим, а события Connect — нет. Как только вы попытаетесь установить соединение, вызвав метод Connect, вызов будет блокирован вплоть до установления соединения или возвращения ошибки.
Кроме того, комплект инструментов VBCE 1.0 не поддерживает массивы элементов управления, а значит, потребуется изменить код серверной части,
приведенный в листинге 15-2. В результате единственный простой способ обработки нескольких соединений — разместить на форме несколько эле- ментов управления Windows CE Winsock. На деле это ограничивает макси- мальное число параллельных клиентских соединений, которое приложение может обработать, поскольку такое решение вообще не масштабируется.
Кроме того, у события ConnectionRequest нет параметра RequestlD, что мо- жет показаться странным. В результате придется вызвать метод Accept для элемента управления, которому будет передано соединение. Запрос на со- единение, вызывающий событие ConnectionRequest, обрабатывается полу- чающим этот запрос элементом управления.
Пример
Рассмотрим вкратце приложение, использующее элемент управления Win- dows СЕ Winsock. Элемент Windows CE Winsock работает аналогично стан- дартному элементу управления Winsock, за исключением описанных разли- чий. В листинге 15-3 приведен код, использующий элемент управления Win- dows СЕ Winsock.
Листинг 15-3. Пример приложения, использующего элемент управления
Windows CE Winsock
Option Explicit
Эта глобальная переменная позволяет сохранить текущее состояние
переключателей. Значение 0 соответствует протоколу TCP, a 2 - протоколу
IrDA (инфракрасный). Учтите, что на данный момент элемент
управления не поддерживает протокол UDP.
Public SocketType

.Элемент управления
495
Листинг 15-3. {продолжение)
Private Sub cmdCloseListen_Click()
)4ol
' Закройте прослушивающий сокет, и верните Я»тим кнопкам
' начальное состояние »н > з i
WinSocki.Close
-'•-vf Ъ
-во dug •
вол ani
cmdConnect.Enabled = True
cmdListen.Enabled = True
cmdDisconnect.Enabled = False
cmdSendData.Enabled = False
cmdCloseListen.Enabled = False
End Sub
«ei
>яэ
МУ
Private Sub cmdConnect_Click() _,я
Э
^
8
j
e v
' Проверьте выбранный тип сокета и инициируйте данное соединение ,о »i
If SocketType = 0 Then
' Задайте протокол, а также имя и номер порта удаленного компьютера
WinSocki.Protocol = 0
nertT S « ^
S » Joooio
WinSocki.RemoteHost = txtServerName.Text
WinSocki. RemotePort = Clnt(txtPort.Text)
WinSocki.LocalPort = 0
WinSocki.Connect
Elself SocketType = 2 Then i »м «отчдохян
-
Выберите протокол IrDA и задайте имя службы
ПьгВ
WinSocki.Protocol = 2 >rtT (S » eJs*a Г
'WinSocki.LocalPort =0 ^ a
fte£dsfi3.lor
'WinSocki.ServiceName = txtServerName.Text le'j
я beliiuoi,m<
WinSockLRemoteHost = txtServerName.Text b©io«n3.n«J«iJ(,
WinSocki.Connect • !пв**л о? sidenU
End If
' Убедитесь, что соединение успешно установлено; вели ето так,
1
включите/отключите некоторые команды
HsgBox WinSocki.State
If (WinSocki.State = 7) Then
cmdConnect.Enabled = False
cmdListen.Enabled = False
cmdDisconnect.Enabled = True
cmdSendData.Enabled = True
Else
MsgBox "Connect failed"
WinSocki.Close
End If
End Sub
50
J3
f l
-9Т 01 ылгкь^ s«
t:*»Itn(!f>»fJt>ns8*xJ >3i
. стр.

496 ЧАСТЬ II Интерфейс прикладндиММЙкаммирования Winsock
Листинг 15-3. (продолжение)
i ti\vt.»
Private Sub cmdDisconnect_Click()
' Закройте соединение текущего клиента
1
и верните кнопкам начальное состояние
WinSocki.Close cmdConnect.Enabled = True cmdListen.Enabled = True cmdDisconnect.Enabled = False cmdSendData.Enabled = False cmdCloseListen.Enabled = False
End Sub
Private Sub cmdListen_Click()
' Переведите сокет в режимы прослушивания для данного типа протокола
If SocketType = 0 Then
WinSocki.Protocol = О
WinSocki.LocalPort = Clnt(txtLocalPort.Text)
WinSocki.Listen
Elself SocketType = 2 Then
WinSocki.Protocol = 2
WinSocki.ServiceName = txtServerName.Text
WinSocki.Listen
End If
' Если сокет находится не в режиме прослушивания,
' возникает ошибка
If (WinSocki.State = 2) Then cmdConnect.Enabled = False cmdListen.Enabled = False cmdCloseListen.Enabled = True
Else
MsgBox "Unable to listen!"
End If
End Sub
Private Sub cmdSendData_Click()
' Передайте данные из рамки по текущему соединению '-'
I
WinSocki.SendData txtSendData.Text
End Sub
. i
Private Sub Form_Load() . >
Задайте начальные значения для кнопок, таймера и т.д. '3
optTCP.Value = True
SocketType = О
Timeri.Interval = 750

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


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