Программирование в сетях Windows. Э. Джонс, Д. Оланд
Скачать 2.88 Mb.
|
ГЛАВА 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 |