VB6 TCP IP-коммуникация без Doevents или подклассов
Что мне нужно сделать с приложением VB6, которое я поддерживаю, так это следующее.
- Установите соединение с известным адресом и портом через сеть Ethernet.
Отправить запрос
Ждите ответа.
Я попытался использовать замену WinSock и Winsock, но все они в той или иной форме используют цикл обмена сообщениями, свойственный различным приложениям Windows. Я не знаю достаточно об Winsock API, как реализовать вышеупомянутый алгоритм в VB6 (или на любом другом языке).
Мое приложение - это программное обеспечение VB6 CAD/CAM, которое управляет металлорежущими станками по выделенной сети Ethernet. Программное обеспечение поддерживается уже 20 лет, и мы разработали несколько драйверов для различных типов контроллеров движения. На сегодняшний день API для этих контроллеров движения состоит из
- Открытие соединения с оборудованием
- Отправка запроса на оборудование (например, Положение оси)
- Ожидание ответа (обычно происходит в миллисекундах).
Некоторые из этих контроллеров работают через сеть Ethernet, но до сих пор мне никогда не приходилось напрямую взаимодействовать с портами. Я использовал поставляемые компанией библиотеки для обработки вещей. И они работают так, как я упоминал выше, и выдают ошибку тайм-аута, если ответ не происходит в течение определенного времени.
Проблема с Winsock заключается в том, что мне нужно вставить DoEvents, чтобы получить ответ. Это вызывает хаос в том, как мы справляемся с многозадачностью в нашем приложении VB6. Замена, такая как CSocketMaster, использует подклассы, которые также вызывают хаос с нашей многозадачностью.
Так что любая помощь о том, как использовать Winsock API или стороннюю DLL, которая может делать то, что мне нужно сделать, как описано выше. Я не спрашиваю, не видел ли я, чтобы другие элементы управления движением делали то, что я хочу.
4 ответа
Я думаю, что редко бывает уместно работать в сети синхронно, однако в традиционном смысле это не сеть. Это провод от ПК к контроллеру. Это как строка между двумя банками. В этом случае с большой старой программой наиболее подходящим является тот, который работает лучше всего и является самым простым в обслуживании. end2cents >
Если VB6 + Winsock не работает для вас, запишите это в.NET и встроите в видимую COM DLL для вашей программы VB6.
Приведенный ниже пример поможет вам начать. Если вы делаете больше, чем случайный вызов, он будет медленным, поскольку он открывает и закрывает соединение при каждом вызове. Его должно быть легко расширить, чтобы можно было повторно использовать открытое соединение для обратной связи между ПК и контроллером. Просто будьте осторожны, чтобы не вызвать утечку памяти!
/// <summary>
/// Sends a message to the specified host:port, and waits for a response
/// </summary>
public string SendAndReceive(string host, int port, string messageToSend, int millisecondTimeout)
{
try
{
using (var client = new TcpClient())
{
client.SendTimeout = client.ReceiveTimeout = millisecondTimeout;
// Perform connection
client.Connect(host, port);
if (client.Connected)
{
using (var stream = client.GetStream())
{
// Convert the message to a byte array
var toSend = Encoding.ASCII.GetBytes(messageToSend);
// Send the message
stream.Write(toSend, 0, toSend.Length);
// Get a response
var response = new byte[client.ReceiveBufferSize];
stream.Read(response, 0, client.ReceiveBufferSize);
return Encoding.ASCII.GetString(retVal);
}
}
else
{
return null;
}
}
}
catch
{
return null;
}
}
Проверьте репозиторий VbAsyncSocket на github для реализации чистых асинхронных сокетов VB6 (используя WSAAsyncSelect
API для сокетов для публикации уведомлений о событиях).
Вопреки своему названию класс поддерживает SyncSendArray
а также SyncReceiveArray
методы для синхронных операций - без DoEvents
но с Timeout
s.
В том же репо есть удобный cWinSockRequest
способствовал класс, который очень похож на WinHttpRequest
объект как запеченный в ОС. Этот вспомогательный класс будет вам очень знаком, если у вас есть опыт работы с JSON/XML (обычно это RESTful-сервисы через http/https) для доступа к сервисам / устройствам через обычные сокеты tcp/udp.
Другой вариант будет использовать cTlsClient
добавленный класс, который может подключаться к хосту / устройству по протоколу TCP (здесь нет udp) и обеспечивает ReadText
/ WriteText
а также ReadArray
/ WriteArray
(синхронно) методы. Дополнительное преимущество заключается в том, что класс поддерживает как обычные незашифрованные сокеты, так и зашифрованные каналы SSL, если это необходимо.
Мы используем эти классы для (синхронного) доступа к принтерам ESP/POS из наших LOB-приложений. Большинство POS-принтеров также предоставляют последовательные (USB-COM-) связи, поэтому мы абстрагируем наши классы доступа с разъемами - SyncWaitForEvent
над асинхронными розетками и WaitForMultipleObjects
на перекрывающихся ReadFile
/ WriteFile
API (о, ирония)
Как оказалось, ответ заключался в реализации предложения Аллена.
Конкретная проблема заключалась в связи между двумя устройствами, участвующими в управлении частью машины. Устройство, которое выполняло управление движением, действует как сервер, в то время как ПК, предоставляющий данные движения, был клиентом.
Сеть Ethernet использовалась вместо проприетарного шинного интерфейса или последовательного интерфейса RS-232/422. Многие из соображений, связанных с обслуживанием данных через широко распространенный Интернет, не были фактором. Сеть состояла из известных устройств с фиксированными IP-адресами, которые прослушивали определенные порты.
После разговора с людьми, которые делают другое управление движением. Логика для клиента оказалась на удивление простой.
- Отправить данные
- Подождите в цикле, чтобы ответ вспыхнул, если он занимает слишком много времени.
- Обрабатывать любые ошибки в соединении.
На стороне сервера нам повезло в том, что мы контролировали программное обеспечение, запущенное на контроллере движения. Таким образом, коммуникационная петля была разработана так, чтобы быть максимально быстрой. Одним из ключевых моментов было держать все данные ниже 512 байт, чтобы они все содержались в одном пакете. Они также очень тщательно расставили приоритеты для обработчика связи и структуры данных, чтобы он мог отправлять ответ за десятки микросекунд.
Другой момент заключался в том, что в этом приложении выделенных клиентов и серверов UDP предпочтительнее, чем TCP, поскольку операционные системы, особенно Windows, имели привычку неожиданно завершать бездействующие соединения TCP.
Потому что клиентское программное обеспечение постепенно переходит на.NET Framework, что было еще одним фактором для реализации идеи Аллена. Библиотека, обсуждаемая @wqw, работала также.
Ваша проблема в том, что вы используете элемент управления Winsock неправильно. Это, вероятно, связано с недостатком вашей модели взаимодействия.
Не "отправляй и жди", потому что блокировать подобное - твоя большая ошибка. В любом случае, нет никакого "ожидания", если только вы не думаете, что сидение в петле гудения ждет.
Вместо этого отправьте запрос и выйдите из этого обработчика событий. Весь ваш код содержится в обработчиках событий, вот как это работает. Затем, когда возникают события DataArrival, вы добавляете новый полученный фрагмент в буфер потока, а затем сканируете собранный поток для получения полного ответа. Затем продолжайте и обработайте ответ.
Обрабатывайте таймауты, используя элемент управления Timer, который вы включаете после отправки. Когда вы соберете законченный ответ, отключите таймер. Если интервал истекает и событие Timer возникает, выполните вашу обработку ошибок там.
Кажется, у вас очень болтливый протокол, поэтому вам не нужно больше ничего делать. Например, вы можете просто очистить буфер потока после обработки полного ответа, поскольку в любом случае там больше ничего не может быть.
Забудьте о "многозадачности" и избегайте вызовов DoEvents(), таких как чума.
Это очень простая вещь.