没有Doevents或子类化的VB6 TCP IP通信

时间:2018-05-02 19:19:34

标签: vb6 winsock winsockets

我维护的VB6应用程序需要做的是以下内容。

  1. 通过以太网建立与已知地址和端口的连接 网络。
  2. 发送请求

  3. 等待回复。

  4. 我尝试使用WinSock和Winsock替换,但他们都依赖于各种Windows应用程序中固有的消息循环。我不太了解Winsock API如何在VB6(或任何其他语言)中实现上述算法。

    我的应用程序是VB6 CAD / CAM软件,可通过专用以太网控制金属切割机。该软件已经维护了20年,我们为不同类型的运动控制器开发了几个驱动程序。迄今为止,这些运动控制器的API由

    组成
    1. 打开与硬件的连接
    2. 向硬件发送请求(例如轴的位置)
    3. 等待回复(通常以毫秒为单位)。
    4. 这些控制器中的一些通过以太网工作,但直到现在我从未必须直接与端口交互。我使用公司提供的库来处理事情。它们以我上面提到的方式工作,并且如果在某个定义的时间内没有响应,则抛出超时错误。

      Winsock的问题是我必须插入DoEvents才能得到响应。这会对我们在VB6应用程序中处理多任务的方式造成严重破坏。像CSocketMaster这样的替代品使用了子类化,这也会对我们的多任务处理造成严重破坏。

      所以有关如何使用Winsock API或第三方dll的任何帮助都可以完成我需要做的事情,如上所述。我不会问我是否还没有看到其他运动控制做我想做的事。

4 个答案:

答案 0 :(得分:2)

在github上查看VbAsyncSocket repo以获取纯VB6异步套接字实现(使用WSAAsyncSelect API为套接字发布事件通知)。

与其名称相反,支持同步操作的SyncSendArraySyncReceiveArray方法 - 没有DoEvents但{{1} }}第

在同一个repo中有一个方便的cWinSockRequest贡献类,它与操作系统中的Timeout对象非常相似。如果您有使用JSON / XML(通常是基于http / https的RESTful服务)的经验,通过普通的tcp / udp套接字访问服务/设备,那么这个帮助程序类将非常适合您。

另一种选择是使用cTlsClient贡献的类,可以通过tcp连接到主机/设备(这里没有udp)并提供WinHttpRequest / ReadTextWriteText / ReadArray(同步)方法。这里的另一个好处是,如果需要,该类支持普通的未加密套接字和SSL加密通道。

我们正在使用这些类来(同步)从我们的LOB应用程序访问ESP / POS打印机。大多数POS打印机也提供串行(USB到COM)链接,因此我们抽象了我们的访问w /连接器类 - SyncWaitForEvent通过异步套接字和WaitForMultipleObjects重叠WriteArray / ReadFile API(哦,具有讽刺意味)

答案 1 :(得分:1)

  

我认为很少适合做网络   同步,但这不是传统意义上的网络。   这是从PC到控制器的电线。这就像一个字符串   两罐之间。在这种情况下,使用大型旧程序,最多   适当的方法是最好的方法,也是最简单的方法   维修。的< / end2cents>

如果VB6 + Winsock没有为您服务,那么在.NET中编写它并将其构建为VB6程序的COM可视DLL将符合要求。

以下示例将帮助您入门。如果你做的不仅仅是偶尔打电话给它,它会很慢,因为它打开并关闭每次通话的连接。它应该很容易扩展,以允许重新使用开放式连接来进行PC和控制器之间的来回通信。请注意,不要造成内存泄漏!

/// <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;
    }
}

答案 2 :(得分:1)

事实证明,答案涉及实施艾伦的建议。

具体问题是在一台机器控制中涉及的两台设备之间进行通信。执行运动控制的设备充当服务器,而提供运动数据的PC则是客户端。

以太网用于代替专用总线接口或RS-232/422串行接口。在广泛的互联网上提供数据所涉及的许多因素都不是一个因素。该网络由驻留在固定IP的已知设备组成,可以监听特定端口。

与做出其他动作控制的人交谈后。事实证明,客户的逻辑非常简单。

  1. 发送数据
  2. 如果花了太长时间,请在循环中等待响应中断。
  3. 处理连接中的任何错误。
  4. 在服务器端,我们很幸运,我们控制了运动控制器上运行的软件。因此,通信环路的设计尽可能快。一个关键点是将所有数据保持在512字节以下,因此它全部包含在一个数据包中。他们还非常谨慎地建立了通信处理程序和数据结构,因此它可以在几十微秒内发出响应。

    另一点是,在专用客户端和服务器的应用程序中,UDP优先于TCP作为操作系统,特别是Windows习惯于意外关闭空闲TCP连接。

    因为客户端软件正在慢慢过渡到.NET框架,这是实现Allen的想法的另一个因素。 @wqw讨论的图书馆工作得很好。

答案 3 :(得分:0)

您的问题是您错误地使用了Winsock控件。这可能源于您的交互模型中的缺陷。

不要发送并等待&#34;因为这样的阻挡是你的大错。没有&#34;等待&#34;无论如何,除非你认为坐在一个嗡嗡声循环中等待。

而是发送您的请求并退出该事件处理程序。您的所有代码都包含在事件处理程序中,以及它的工作原理。然后,当引发DataArrival事件时,将新到达的片段附加到流缓冲区,然后扫描汇编的流以获得完整的响应。然后继续处理响应。

使用您在发送后启用的Timer控件处理超时。组装完成的响应后,禁用Timer。如果间隔过去并且提升了Timer事件,那么请在那里进行错误处理。

你似乎有一个特别繁琐的协议,所以你不应该做任何其他事情。例如,您可以在处理完整响应后清除流缓冲区,因为无论如何都不会留下任何其他内容。

忘掉&#34;多任务&#34;并避免像他们那样的瘟疫之类的DoEvents()调用。

这是非常简单的东西。