Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Использование Winsock контрола

Oleg Palayda Апрель 2000

Этот текст является вольным переводом из MSDN и демонстрирует возможности обмена данными по сети при помощи компонента Winsock.

Кое-что дополнено и исправлена одна ошибка из сэмпла MSDN из-за которой передача шла только в одну сторону.

Использование компонента Winsock

Компонент WinSock позволяет соединиться с удаленной машиной и обменяться с ней данными, используя UDP (User Datagram Protocol) или TCP (Transmission Control Protocol). Оба протокола могут быть использованы при создании клиент-серверных приложений. Также, как и Timer control, WinSock control является невидимым во время выполнения программы.

Как им пользоваться?

- cоздать приложение-клиент, которое будет собирать информацию перед отсылкой ее на центральный сервер;

- cоздать приложение-сервер, которое будет выполнять роль сборщика и хранителя информации от различных клиентских приложений;

- создать "chat"-приложение.

Выбор протокола.

Когда планируется использование а WinSock, необходимо решить какой протокол будет использоваться - TCP или UDP. Основное отличие между ними заключается в способе организации связи:

Соединение основанное на TCP протоколе, похоже на телефонное - пользователь сначала должен установить соединение, прежде чем что-либо передавать.

Соединение основанное на UDP протоколе, похоже на передачу голосом, сообщение передается от одного компьютера к другому, но не ясно, слышат ли они друг друга. Вдобавок, максимальный размер предаваемых данных устанавливается сетью.

Возможности приложения которое Вы создаете будет зависеть от протокола, который Вы изберете. Вот несколько вопросов которые могут помочь Вам выбрать подходящий протокол: Будет ли приложение требовать уведомления от сервера или клиента, когда данные передаются или получаются?

Если будет, то TCP протокол требует установленного соединения между передатчиком и приемником данных.

Будут ли передаваемые данные достаточно тяжелыми (например изображения или звуковые файлы)? Если соединение было установлено, TCP протокол будет его поддерживать и гарантируется целостность передаваемых данных. Такое соединение, из-за потребности в большем количестве вычислительных ресурсов, может сделать его более медленным.

Будут ли данные передаваться порциями или за одну сессию? Например, если Вы создаете приложение, которое сообщает каким-то компьютерам, о том, что какие-то задачи уже выполнены, то UDP протокол более подходящий. UDP протокол также блучше подходит для передачи небольшого количества данных.

Установка протокола.

Чтобы установить протокол, который будет использовать ваше приложение Вы должны в дизайн-тайме в окне свойств выбрать свойство Protocol и установить его sckTCPProtocol или sckUDPProtocol. Это можно также сделать программно:

Winsock1.Protocol = sckTCPProtocol

Определение имени компьютера.

Чтобы установить связь с удаленным компьютером, Вы должны знать либо его IP-адресс, либо его имя.

Основы TCP соединения.

Когда создается приложение, которое использует TCP протокол первое, что Вы должны решить, это чем будет ваше приложение клиентом или сервером. Если Вы создаете приложение-сервер, значит ваше приложение будет слушать указанный порт. Когда приложение-клиент подаст запрос на соедиение, приложение-сервер может принять запрос и таким образом установить соедиенеие. Если соединение установлено, приложение-клиент и приложение сервер могут свободно обмениваться данными.

Следующие шаги позволят Вам создать элементарное приложение-сервер:

Для создания TCP сервера

  • Создайте новый Standard EXE проект.
  • Замените имя формы по умолчанию на frmServer.
  • В свойстве формы caption наберите "TCP Server"
  • В меню Project\Components добавьте Microsoft Winsock Conrol 6.0
  • Перетащите иконку компонента Winsock с панели инструментов и разместите ее на форме; измените имя компонента на tcpServer.

Добавьте на форму два Текстбокс элемента. В свойстве Name первого текстового поля наберите txtSendData, а второго txtOutput.

Добавьте в форму следующий код:

   Private Sub Form_Load()
    'Задать номер порта по которому будет осуществляться
   'обмен данными, присвоив значение свойству LocalPort
   'Вызвать метод Listen.
   tcpServer.LocalPort = 1001
   tcpServer.Listen
   frmClient.Show 'Показать форму клиента
   End Sub
   
   Private Sub tcpServer_ConnectionRequest _
   (ByVal requestID As Long)
   ' Проверяется свойство State, было ли завершено
   ' предыдущее соединение. Если не завершено,
   ' то перед установлением нового соединения,
   ' старое закрывается принудительно.
   If tcpServer.State  sckClosed Then _
   tcpServer.Close
   ' Принятие запроса Accept с параметром requestID
   ' на установление соедиения.
   tcpServer.Accept requestID
   End Sub
   
   Private Sub txtSendData_Change()
   ' Текстовое поле txtSendData
   ' содержит данные для передачи. Все символы,
   ' которые будут вводиться в это текстовое поле, будут единой
   ' строкой посылаться приложению-клиенту, используя метод SendData.
   tcpServer.SendData txtSendData.Text
   End Sub
   
   Private Sub tcpServer_DataArrival _
   (ByVal bytesTotal As Long)
   ' Декларируется переменная-буфер для получаемых данных.
   ' Вызывается метод GetData и свойству Text
   ' текстового поля txtOutput, присваивается значение переменной-
   ' буфера.
   Dim strData As String
   tcpServer.GetData strData
   txtOutput.Text = strData
   End Sub
   

Описанные выше действия, выполненные Вами, приведут к созданию простого приложения-сервера. Но для того чтобы полностью выполнить задачу, необходимо создать еще и приложение-клиент.

Для создания TCP приложения-клиента

Добавьте новую форму в проект и назовите ее frmClient. И змените свойство формы caption на "TCP Client".

Перетащите и разместите компонент Winsock на форму и измените его свойство name на "tcpClient".

  • Добавьте два Текстбокс-контрола на форму frmClient.
  • Имя первого установите txtSend, а второго txtOutput.
  • Перетащите на форму CommandButton и установите его свойство name в "cmdConnect".
  • Измените свойство caption этой кнопки на "Connect".

Добавьте следующий код в форму.

Важно!!! Будьте внимательны при установке свойства RemoteHost. Оно должно соответствовать либо IP-адресу вашего компьютера, либо его "Дружественному имени" (см. Пуск\Настройка\Панель управления\Сеть) выберите вкладку "Идентификация". Текст из поля "Имя компьютера" и будет так называемым дружественным именем, которым можно заменять IP-адрес. Сам же IP-адрес, можно посмотреть, если выбрать закладку "Конфигурация" в списке выбрать TCP/IP, нажать кнопку "Свойства" и выбрать закладку IP-адрес.

Private Sub Form_Load()
' Имя Winsock-компонента tcpClient.
' Указывая имя удаленного компьютера можно
' указывать IP-адрес (например: "121.111.1.1") или
' дружественное имя, как в нижеприведенном коде.
tcpClient.RemoteHost = "RemoteComputerName" 'или "121.111.1.1"
tcpClient.RemotePort = 1001
End Sub

Private Sub cmdConnect_Click()
' Вызвать метод Connect для создания соединения
tcpClient.Connect
End Sub

Private Sub txtSend_Change()
tcpClient.SendData txtSend.Text
End Sub

Private Sub tcpClient_DataArrival _
(ByVal bytesTotal As Long)
Dim strData As String
tcpClient.GetData strData
txtOutput.Text = strData
End Sub

Сохраните проект в отдельной директории.

Код приведенный выше - это простейшее клиент-серверное приложение. Чтобы попробовать, как это все работает на одной машине в связке, имитирующей межмашинное соединение, значение свойства RemoteHost приложения-клиента должно соответствовать дружественному имени или IP-адресу вашего компьютера. Запустите проект и нажмите кнопку "Connect". После этого наберите текст внутри текстового поля txtSendData на каждой форме и убедитесь, что тот же самый текст появится в текстовом поле txtOutput другой формы.

Если Вы хотите, попробовать, как приложения будут осуществлять связь между двумя компьютерами, то Вам прийдется произвести следующие действия:

  • Удалить из кода формы приложения-сервера строку frmClient.Show.
  • В окне Project Explorer щелкнуть правой кнопкой мыши на форме frmClient.frm и в появившемся меню выбрать Remove frmClient.frm после чего сохранить проект под именем Server1.
  • Открыть первый вариант проекта и таким же образом удалить из проекта уже форму frmServer.frm.
  • Создать exe модуль для frmClient-а и переписать его на удаленный компьютер и запустить его там.

Примечание: если на удаленном компьютере не установлен VB будьте готовы к тому, что вам потребуется переписать на него из WINDOWS\SYSTEM\mswinsck.ocx и зарегистрировать его при помощи команды WINDOWS\SYSTEM\regsvr32.exe mswinsck.ocx

Если приложение будет требовать какие-то дополнительные dll модули перепишите их со своей машины на удаленную.

  • На своей машине, откройте проект Server и запустите его.
  • На клиентской машине нажмите кнопку Connect и наберите текст внутри текстового поля txtSendData на каждой форме и убедитесь, что тот же самый текст появится в текстовом поле txtOutput в приложении, запущенном на другом компьютере.

Обработка более чем одного запроса на установление соединения.

Приложение-сервер, которое мы создавали сначала может обработать только один запрос на соединение. Тем не менее, существует возможность обработать несколько запросов на соединение, используя тот же самый управляющий элемент как один из массива управляющих элементов.

В этом случае, необязательно закрывать соединение - просто создайте новый вариант управляющего элемента (использовав его свойство Index) и вызовите метод Accept для этого нового варианта управляющего элемента.

В приведенном ниже тексте программы, свойству Index, размещенного на форме Winsock-компонента sckServer, присваивается значение 0, таким образом, управляющий элемент становится частью массива управляющих элементов. В разделе Declarations описана локальная переменная intMax. Когда для формы происходит событие Load, переменной intMax присваивается значение 0 и свойству LocalPort первого элемента массива управляющих элементов присваивается значение 1001. Только после того, как вызывается метод Listen этого управляющего элемента, он начинает слушать указанный порт. Когда поступает новый запрос на соединение, осуществляется проверка значения Index и равно ли оно 0 (значение элемента, который слушает порт). Таким образом, элемент который слушает порт, будет приращивать переменную intMax и использовать значение этой переменной для создания нового элемента массива. Этот новый элемент будет использоваться для обработки запроса на соединение.

Private intMax As Long

Private Sub Form_Load()
intMax = 0
sckServer(0).LocalPort = 1001
sckServer(0).Listen
End Sub

Private Sub sckServer_ConnectionRequest _
(Index As Integer, ByVal requestID As Long)
If Index = 0 Then
intMax = intMax + 1
Load sckServer(intMax)
sckServer(intMax).LocalPort = 0
sckServer(intMax).Accept requestID
Load txtData(intMax)
End If
End Sub

Основы UDP.

Создавать приложения, использующие UDP протокол проще, чем создавать приложения, использующие TCP протокол. Дело в том, что UDP не требует уже установленного соединения, как необходимого условия для передачи данных. В приложениях использующих TCP соединение, один Winsock элемент должен обязательно "слушать" порт, в ожидании пока какое-нибудь другое приложение не станет инициатором соединения, использовав метод Connect.

UDP протокол не требует обязательно установленного соединения для передачи данных. Для передачи данных между двумя приложениями, необходимо выполнить три следующих пункта с обеих соединяющихся сторон:

  • присвоить свойству RemoteHost дружественное имя или IP-адрес компьютера с которым предстоит соединение;
  • установить свойство RemotePort для LocalPort property of the second control.
  • Вызвать метод Bind указав какой локальный порт будет использоваться (метод Bind подробнее будет обсужден ниже).

Т.к. оба компьютера полагаются равными в установлении соединения, мы можем назвать это соединение peer-to-peer. Чтобы продемонстрировать это соединение мы создадим так называемое приложение-chat позволяющее двум людям общаться в реальном режиме времени.

Для создания UDP соединения:

Создайте Standard EXE проект.

  • Измените свойство name формы на frmPeerA.
  • Измените свойство caption формы на "Peer A"
  • Перетащите с панели инструментов иконку Winsock компонента и разместите его на форме. Присвойте свойству name значение udpPeerA.
  • Измените свойство Protocol на UDPProtocol.
  • Добавьте два текстовых поля на форму.

Имя первой должно быть txtSend а второй txtOutput. Добавьте приведенный ниже код на форму.

Private Sub Form_Load()
' Имя Winsock элемента udpPeerA
With udpPeerA
' Важно: правильно укажите значение RemoteHost
' компьютера, с которым предстоит соединение.
.RemoteHost= "PeerB"
.RemotePort = 1001 ' Имя порта для соединения.
.Bind 1002 ' Привязка к локальному порту.
End With
frmPeerB.Show ' Показать вторую форму.
End Sub

Private Sub txtSend_Change()
' Послать текст, как только он будет набран.
udpPeerA.SendData txtSend.Text
End Sub

Private Sub udpPeerA_DataArrival _
(ByVal bytesTotal As Long)
Dim strData As String
udpPeerA.GetData strData
txtOutput.Text = strData
End Sub

Чтобы создать второе UDP приложение.

  • Добавить стандартную форму в проект.
  • Изменить имя формы на frmPeerB.
  • Изменить свойство caption формы на "Peer B".
  • Перетащить и разместить иконку Winsock компонента на форму.
  • Изменить имя Winsock на udpPeerB.
  • Изменить свойство Protocol на UDPProtocol.
  • Добавить два текстовых поля на форму.

Имя первого должно быть txtSend, а второго txtOutput.

Добавьте следующий код в форму.

Private Sub Form_Load()
' Имя Winsock элемента udpPeerB.
With udpPeerB
' Будьте внимательны указывая имя или IP-адрес
' компьютера с которым предстоит соединение.
.RemoteHost= "PeerA"
.RemotePort = 1002 ' Номер порта для соединения.
.Bind 1001 ' Привязка к локальному порту.
End With
End Sub

Private Sub txtSend_Change()
' Пересылать текст, как только он будет набран в текстовом поле.
udpPeerB.SendData txtSend.Text
End Sub

Private Sub udpPeerB_DataArrival _
(ByVal bytesTotal As Long)
Dim strData As String
udpPeerB.GetData strData
txtOutput.Text = strData
End Sub

Чтобы попробовать приложение запустите проект, и наберите в текстовом поле txtSend каждой формы какой-то текст.

Этот текст появится в текстовых полях txtOutput другой формы.

О методе Bind.

Как показано в приведенном выше примере, Вы должны вызывать метод Bind, когда создается UDP приложение. Метод Bind резервирует локальный порт для использования его элементом Winsock. Например, когда Вы привязываете свой элемент Winsock к порту 1001, то ни одно другое приложение не может использовать этот порт для прослушивания. Это может быть полезным, когда Вы хотите воспрепятствовать какому-либо другому приложению использовать этот порт.

Метод Bind имеет еще один необязательный аргумент.

Если на вашем компьютере установлено более одного сетевого адаптера, аргумент LocalIP позволит Вам точно указать адаптер, который необходимо использовать. Если Вы не укажите этот аргумент, то Winsock компонент будет использовать тот сетевой адаптер, который расположен первым в списке, который можно посмотреть в Пуск\Настройка\Панель управления\Система\Сетевые платы.

Когда используется UDP протокол, Вы можете изменять свойства RemoteHost и RemotePort пока сохраняется привязка к тому же самому LocalPort. Если бы Вы использовали TCP протокол, то прежде чем сменить свойства RemoteHost и RemotePort, необходимо сначала закрыть соединение.

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 

Комментарии

1.
31K
04 июля 2007 года
Arthur1
0 / / 04.07.2007
Мне нравитсяМне не нравится
4 июля 2007, 22:38:31
Thank you!
2.
28K
11 апреля 2007 года
olegteror
0 / / 11.04.2007
Мне нравитсяМне не нравится
23 мая 2007, 00:40:03

Цитата:
только вот в VB.NET - это не так просто :(


Эт точно

3.
12K
03 августа 2005 года
Lepshiy
1 / / 03.08.2005
Мне нравитсяМне не нравится
21 августа 2006, 11:55:19
ОЧЕНЬ ОТЛИЧНО ПОЛУЧИЛОСЬ, ВОТ ЧТО СДЕЛАЛ Я:
НА ФОРМУ РАЗМЕСТИТЬ:

udpPeerA - WINSOCK НА UDP
txtOutput - Текстбокс-контрол
txtNick - Текстбокс-контрол
txtSend - Текстбокс-контрол
lstIP - ЛИСТБОКС-КОНТРОЛ ЗДЕСЬ ВПИСЫВАЮТСЯ ЛИБО АДРЕСА МАШИН ИЛИ ИХ ИМЕНА (ВСЕ КТО БУДЕТ В ЧАТЕ)

ON ERROR RESUME NEXT - ПОСКОЛЬКУ НЕТ АВТОМАТИЧЕСКОГО АПРЕДЕЛЕНИЯ МАШИН ТО ЭТО НУЖНО ЧТОБЫ НЕ ВЫЛЕТАЛА ОШИБКА ПРИ ОТПРАВКЕ СООБЩЕНИЯ ЕСЛИ 1 МАШИНЫ В СПИСКЕ НЕТ. ЕСЛИ ВСЕ МАШИНЫ ЗАГРУЗИЛИ ЧАТ КОТОРЫЕ В СПИСКЕ ТО ЭТО НЕ НУЖНО.
----------------------------------------------------------------------

Private Sub Form_Load()
With udpPeerA
.Bind 1001 ' Привязка к локальному порту.
End With
End Sub

Private Sub txtSend_KeyPress(KeyAscii As Integer)
On Error Resume Next
Dim x, y
Dim X_SendData

x = lstIP.ListCount - 1

If KeyAscii = vbKeyReturn Then
X_SendData = "[" & Time & "] " & txtNick.Text & ": " & txtSend.Text & vbCrLf

For y = 0 To x
With udpPeerA
.RemoteHost = lstIP.List(y)
.RemotePort = 1001
.SendData X_SendData
End With
Next y

txtOutput.Text = txtOutput.Text & X_SendData
txtSend.Text = ""
End If
End Sub


Private Sub udpPeerA_DataArrival(ByVal bytesTotal As Long)
Dim strData As String
udpPeerA.GetData strData
txtOutput.Text = txtOutput.Text & strData
End Sub

----------------------------------------------------------------------
ДА И СРАЗУ ПОПУТНЫЙ ВОПРОС КАК СДЕЛАТЬ ТАК ЧТО БЫ ПРИ ЗАГРУЗКЕ ЧАТА ОПРЕДЕЛЯЛИСЬ ВСЕ ЗАГРУЖЕННЫЕ МАШИНЫ С ЭТИМ ЧАТОМ... Т.Е. ЧТО БЫ ВРУЧНУЮ НЕ ВВОДИТЬ В ИСХОДНИКЕ МАШИНЫ?
4.
12K
03 августа 2005 года
Lepshiy
1 / / 03.08.2005
Мне нравитсяМне не нравится
21 августа 2006, 11:51:15
ОЧЕНЬ ОТЛИЧНО ПОЛУЧИЛОСЬ, ВОТ ЧТО СДЕЛАЛ Я:
НА ФОРМУ РАЗМЕСТИТЬ:

udpPeerA - WINSOCK НА UDP
txtOutput - Текстбокс-контрол
txtNick - Текстбокс-контрол
txtSend - Текстбокс-контрол
lstIP - ЛИСТБОКС-КОНТРОЛ ЗДЕСЬ ВПИСЫВАЮТСЯ ЛИБО АДРЕСА МАШИН ИЛИ ИХ ИМЕНА (ВСЕ КТО БУДЕТ В ЧАТЕ)

ON ERROR RESUME NEXT - ПОСКОЛЬКУ НЕТ АВТОМАТИЧЕСКОГО АПРЕДЕЛЕНИЯ МАШИН ТО ЭТО НУЖНО ЧТОБЫ НЕ ВЫЛЕТАЛА ОШИБКА ПРИ ОТПРАВКЕ СООБЩЕНИЯ ЕСЛИ 1 МАШИНЫ В СПИСКЕ НЕТ. ЕСЛИ ВСЕ МАШИНЫ ЗАГРУЗИЛИ ЧАТ КОТОРЫЕ В СПИСКЕ ТО ЭТО НЕ НУЖНО.
----------------------------------------------------------------------

Private Sub Form_Load()
With udpPeerA
.Bind 1001 ' Привязка к локальному порту.
End With
End Sub

Private Sub txtSend_KeyPress(KeyAscii As Integer)
On Error Resume Next
Dim x, y
Dim X_SendData

x = lstIP.ListCount - 1

If KeyAscii = vbKeyReturn Then
X_SendData = "[" & Time & "] " & txtNick.Text & ": " & txtSend.Text & vbCrLf

For y = 0 To x
With udpPeerA
.RemoteHost = lstIP.List(y)
.RemotePort = 1001
.SendData X_SendData
End With
Next y

txtOutput.Text = txtOutput.Text & X_SendData
txtSend.Text = ""
End If
End Sub


Private Sub udpPeerA_DataArrival(ByVal bytesTotal As Long)
Dim strData As String
udpPeerA.GetData strData
txtOutput.Text = txtOutput.Text & strData
End Sub

----------------------------------------------------------------------
ДА И СРАЗУ ПОПУТНЫЙ ВОПРОС КАК СДЕЛАТЬ ТАК ЧТО БЫ ПРИ ЗАГРУЗКЕ ЧАТА ОПРЕДЕЛЯЛИСЬ ВСЕ ЗАГРУЖЕННЫЕ МАШИНЫ С ЭТИМ ЧАТОМ... Т.Е. ЧТО БЫ ВРУЧНУЮ НЕ ВВОДИТЬ В ИСХОДНИКЕ МАШИНЫ?
5.
Аноним
Мне нравитсяМне не нравится
1 мая 2006, 03:32:19
только вот в VB.NET - это не так просто :(
6.
Аноним
Мне нравитсяМне не нравится
21 февраля 2006, 18:14:42
Супер долго искал человеческим языком.
7.
Аноним
Мне нравитсяМне не нравится
17 января 2006, 09:34:30
Я думаю всего этого достаточно!
Если кому мало, то пусть почитает свойства в окне "object browser" для этого контролла. Много интересного :)
8.
Аноним
Мне нравитсяМне не нравится
30 сентября 2005, 14:18:14
Скажите есть ли принцыпиальные отличия в использованиии winsock в vb.net ??
если есть , то какие?
9.
Аноним
+1 / -0
Мне нравитсяМне не нравится
18 августа 2005, 17:28:39
Люди, помогите с автоматическим восстановлением соединения между клиентом и сервером, после отключения сервера.
10.
Аноним
Мне нравитсяМне не нравится
8 августа 2005, 00:53:15
Подскажите, а где можно достать полную инфу по WinSock. Буду очень признателен!
11.
Аноним
Мне нравитсяМне не нравится
3 мая 2005, 02:30:12
Хорошая тема, буду следить за ее развитеем.
12.
Аноним
Мне нравитсяМне не нравится
14 апреля 2005, 13:00:19
А для обработки нескольких запросов на соединение обязательно создавать массив елементов или можно как-то по другому? И это всё работает на одном порту? В том смысле, что если кто-то один законектился и получает данные на 1001 то остальные тоже смогут соединится на 1001?
13.
Аноним
Мне нравитсяМне не нравится
4 апреля 2005, 16:04:10
а у меня рантайм эрроры. Это к чему?
14.
Аноним
Мне нравитсяМне не нравится
4 июля 2004, 20:31:44
Весьма просто и понятно,спасибо. А по подробнее будет?
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог