-1

我尝试在 DLL 中进行一些 modbus 以太网 tcp 通信。如 WireShark 中所示,我从目标设备获得了大量 TCP 重传。

在此处输入图像描述

(在此图中,192.168.1.5 是 Modbus 设备。192.168.1.72 是计算机)

但是,将相同的代码直接插入应用程序时,不会出现通信错误。

我想知道 DLL 是否具有某种可能导致通信速度变慢的较低优先级,或者是否有人可能对为什么此代码在应用程序中运行而没有 TCP 问题而不在 DLL 中运行有任何见解。

这是dll头:

#ifndef __MAIN_H__
#define __MAIN_H__

#include <windows.h>

typedef void *eioTHandle;


#ifdef __cplusplus
extern "C"
{
#endif

__declspec(dllexport) int __stdcall eioConnect( unsigned short ModelId, char *Ip, eioTHandle *Handle );

#ifdef __cplusplus
}
#endif

#endif

这是源文件:

#include "main.h"
#include <winsock2.h>
#include <ws2tcpip.h>

#include <stdint.h>

#define EIO500_S                        0
#define EIO500_MS                       1000

#define eioERROR    -1
#define eioSUCCESS   0

static uint8_t m_UnitId = 0xff;
static SOCKET m_Sock;


BOOL WINAPI DllMain(HINSTANCE hinstDLL,  DWORD fdwReason, LPVOID lpReserved )
{
    // Perform actions based on the reason for calling.
    switch( fdwReason )
    {
        case DLL_PROCESS_ATTACH:
         // Initialize once for each new process.
         // Return FALSE to fail DLL load.
            break;

        case DLL_THREAD_ATTACH:
         // Do thread-specific initialization.
            break;

        case DLL_THREAD_DETACH:
         // Do thread-specific cleanup.
            break;

        case DLL_PROCESS_DETACH:
         // Perform any necessary cleanup.
            break;
    }
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}


int __stdcall eioConnect( unsigned short ModelId, char *Ip, eioTHandle *Handle )
{

    WSADATA Wsa;
    struct sockaddr_in Server;

    int Result;
    char Buffer[256];
    char InBuffer[256];

    // CONNECTION --------------------------------------------------------------
    if (WSAStartup(MAKEWORD(2,2), &Wsa) != 0)
    {
        return eioERROR;
    }

    m_Sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (m_Sock == INVALID_SOCKET)
    {
        WSACleanup();
        return eioERROR;
    }

    Server.sin_addr.s_addr = inet_addr(Ip);
    Server.sin_family = AF_INET;
    Server.sin_port = htons(502);

    if (connect(m_Sock, (struct sockaddr *)&Server, sizeof(Server))
        == SOCKET_ERROR)
    {
        closesocket(m_Sock);
        m_Sock = INVALID_SOCKET;
        WSACleanup();
        return eioERROR;
    }
    // -------------------------------------------------------------------------

    for (int Ctr = 0; Ctr < 50000; Ctr++)
    {


        // SEND COMMAND --------------------------------------------------------
        // 5 bytes in a Send Read Multiple Coils command.
        int NumBytes = 5;

        Buffer[0] = 0;
        Buffer[1] = 0;
        Buffer[2] = 0;
        Buffer[3] = 0;
        Buffer[4] = 0;
        Buffer[5] = NumBytes + 1;   // 1 for unit id.
        Buffer[6] = m_UnitId;

        // 0 = Function code.
        Buffer[7] = 0x01;

        // 1+2 = Address.
        Buffer[8] = 0;
        Buffer[9] = 8;

        // 3+4 = Number of bits to read.
        Buffer[10] = 0;
        Buffer[11] = 8;

        if (send(m_Sock, Buffer, NumBytes + 7, 0) == SOCKET_ERROR)
        {
            continue;
        }

        // ---------------------------------------------------------------------


        // WAIT FOR RECEIVE ----------------------------------------------------
        WSAEVENT RecvEvent;
        int Ret;

        RecvEvent = WSACreateEvent();

        WSAEventSelect( m_Sock, RecvEvent, FD_READ );

        Ret = WSAWaitForMultipleEvents(1, &RecvEvent, TRUE, 1000, FALSE);

        WSAResetEvent(RecvEvent);

        if (Ret == WSA_WAIT_TIMEOUT)
            continue;
        // -------------------------------------------------------------------------



        // Check for any reply.
        recv(m_Sock, InBuffer, 256, 0);


    }


    // DISCONNECT --------------------------------------------------------------
    Result = shutdown(m_Sock, SD_SEND);

    if (Result == SOCKET_ERROR)
    {
        closesocket(m_Sock);
        WSACleanup();
        m_Sock = INVALID_SOCKET;
        return eioERROR;
    }

    // Receive until the peer closes the connection.
    while (recv(m_Sock, Buffer, 256, 0) > 0);

    closesocket(m_Sock);
    WSACleanup();

    m_Sock = INVALID_SOCKET;
    // ------------------------------------------------------------------------

    return eioSUCCESS;

}

我已经尽可能地简化了代码。通信在循环中进行测试。原始应用程序将从设备轮询此数据。

4

1 回答 1

0

不。从网络的角度来看,以某种方式发送的 TCP 段没有区别。但是,可能存在协议优先级(QoS),当链路饱和时可能会导致数据包丢失。

更可能的原因可能是校验和的问题:无效的校验和导致数据包丢失,进而导致重新传输。从 DLL 调用时,API 的工作方式可能略有不同,因此(正确)计算校验和。

于 2018-04-12T10:59:25.140 回答