简体   繁体   English

具有多个从站ID的Modbus TCP客户端服务器

[英]modbus tcp client server with multiple slave id

I'm working on win ce 6 modbus tcp client server, application is developed for a client server communication and it is working fine. 我正在使用win ce 6 modbus tcp客户端服务器,该应用程序是为客户端服务器通信而开发的,并且工作正常。 now req is my slave device should respond to the diff slave addresses polled by master/client. 现在要求是我的从设备应该响应主/客户端轮询的diff从地址。 Can I just change slave id and establish connection or I need to close previous connection and again establish new one 我可以只更改从站ID并建立连接,还是需要关闭先前的连接并再次建立新的连接

below is the code, which is working fine for one node, if I polled with other node ID then it gives exception. 下面是代码,它对于一个节点正常工作,如果我使用其他节点ID进行轮询,则会给出异常。 what change it req to communicate with other node simultaneously. 它需要什么更改才能与其他节点同时通信。 My device should be able to communicate with 32 diff nodes on modbus tcp. 我的设备应该能够与Modbus tcp上的32个差异节点进行通信。 Shall I create individual threads for each node but how they will communicate on same port? 我应该为每个节点创建单独的线程,但是它们将如何在同一端口上通信? before establishing connection with other node shall I close previous node? 在与其他节点建立连接之前,我应该关闭上一个节点吗?

startupServer(int slaveAddr,  const TCHAR * const hostName)
{

   int result;
   int tcpOption;
   struct sockaddr_in hostAddress;

   if (isStarted())
      return (FTALK_ILLEGAL_STATE_ERROR);

   // Note: For TCP we allow 0 as slave address, -1 means ignore slave adr
   if ((slaveAddr < -1) || (slaveAddr > 255))
      return (FTALK_ILLEGAL_ARGUMENT_ERROR);
   this->slaveAddr = slaveAddr;

   //
   // Special treatment for the Win32 platform, needs to load WinSock DLL
   //
#ifdef _WINSOCKAPI_
   WSADATA wsaData;

   result = WSAStartup(0x0101, &wsaData);
   if (result != 0)
      return (FTALK_SOCKET_LIB_ERROR);
#endif

   //
   // Open socket
   //
   listenSocket = socket(PF_INET, SOCK_STREAM, 0);
   if (listenSocket == INVALID_SOCKET)
   {
      shutdownServer();
      return (FTALK_OPEN_ERR);
   }

   //
   // Configure listen socket options (we ignore errors here)
   //
#ifdef SO_REUSEADDR
   tcpOption = 1; // Enable option
   setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR,
              (char *) &tcpOption, sizeof (tcpOption));
#endif

   //
   // Binding the listen socket to the port
   //
   hostAddress.sin_family = AF_INET;
   if ((hostName == NULL) || (hostName[0] == '\0'))
      hostAddress.sin_addr.s_addr = htonl(INADDR_ANY);
   else
   {
      hostAddress.sin_addr.s_addr = inet_addr((char *) hostName);
#if !defined(__VXWORKS__) // We don't support host name resolving with VxWorks
      if (hostAddress.sin_addr.s_addr == INADDR_NONE)
      {
         struct hostent *hostInfo;

         hostInfo = gethostbyname((char *) hostName);

         if (hostInfo == NULL)
            return (FTALK_TCPIP_CONNECT_ERR);
         hostAddress.sin_addr = *(struct in_addr *) hostInfo->h_addr;
      }
#endif
   }
   hostAddress.sin_port = htons(portNo);
   result = bind(listenSocket, (struct sockaddr *) &hostAddress,
                 sizeof (hostAddress));
   if (result == SOCKET_ERROR)
   {
      shutdownServer();
      switch (socketErrno)
      {
#ifdef _WINSOCKAPI_
         case WSAEACCES:
         return (FTALK_PORT_NO_ACCESS);
         case WSAEADDRINUSE:
         return (FTALK_PORT_ALREADY_BOUND);
         case WSAEADDRNOTAVAIL:
         default:
         return (FTALK_PORT_NOT_AVAIL);
#else
         case ENOTCONN: // Linux 7.2 reports this error no if no root privilege
         case EACCES:
         return (FTALK_PORT_NO_ACCESS);
         case EADDRINUSE:
         return (FTALK_PORT_ALREADY_BOUND);
         case EADDRNOTAVAIL:
         default:
         return (FTALK_PORT_NOT_AVAIL);
#endif
      }
   }

   //
   // Start listening to incoming connections
   //
   result = listen(listenSocket,
               ((MAX_CONNECTIONS < SOMAXCONN) ? MAX_CONNECTIONS : SOMAXCONN));
   if (result == SOCKET_ERROR)
   {
      shutdownServer();
      return (FTALK_LISTEN_FAILED);
   }
   return (FTALK_SUCCESS);
}

serverLoop()
{
   int iReturnCode = (FTALK_SUCCESS);
   int result;
   int sockIdx;
   int recvResult;
   int sendResult;
   fd_set fdSet;
   timeval timeVal;
   SOCKET maxFileDes;
   int replyCnt;
   int tcpOption;

   if (!isStarted())
      return (FTALK_ILLEGAL_STATE_ERROR);

   //
   // Prepare file descriptor set for select call
   //
   FD_ZERO (&fdSet);
#ifdef _MSC_VER
#  pragma warning(push)
#  pragma warning(disable: 4127)
#endif
   FD_SET (listenSocket, &fdSet);
#ifdef _MSC_VER
#  pragma warning(pop)
#endif
   maxFileDes = listenSocket;
   for (sockIdx = 0; sockIdx < MAX_CONNECTIONS; sockIdx++)
   {
      if (connectionSocketArr[sockIdx] != INVALID_SOCKET)
#ifdef _MSC_VER
#  pragma warning(push)
#  pragma warning(disable: 4127)
#endif
         FD_SET (connectionSocketArr[sockIdx], &fdSet);
#ifdef _MSC_VER
#  pragma warning(pop)
#endif
      if (connectionSocketArr[sockIdx] > maxFileDes)
         maxFileDes = connectionSocketArr[sockIdx];
   }

   //
   // Block until accept request or received data or time-out
   //
   timeVal.tv_sec = (long) timeOut / 1000L;
   timeVal.tv_usec = ((long) timeOut % 1000L) * 1000L;
   if (timeOut == 0)
      result = select((int) maxFileDes + 1, &fdSet, NULL, NULL, NULL);
   else
      result = select((int) maxFileDes + 1, &fdSet, NULL, NULL, &timeVal);
   if (result == SOCKET_ERROR)
      return (FTALK_FILEDES_EXCEEDED);

   //
   // Check for time-out
   //
   if (result == 0)
   {
      TRACELOG1("Slave poll time-out!\n");
      dataTablePtr->timeOutHandler();

      iReturnCode = (FTALK_REPLY_TIMEOUT_ERROR);
   }

   //
   // Connection accept request
   //
   if (FD_ISSET (listenSocket, &fdSet))
   {
      // Search a free socket
      for (sockIdx = 0; sockIdx < MAX_CONNECTIONS; sockIdx++)
      {
         if (connectionSocketArr[sockIdx] == INVALID_SOCKET)
         {
            struct sockaddr_in peerAddr;
            SOCK_LEN_TYPE peerAddrLen = sizeof(peerAddr);

            // Yes, socket is free, try to accept a connection on it
            connectionSocketArr[sockIdx] = accept(listenSocket,
                                                  (struct sockaddr *) &peerAddr,
                                                  &peerAddrLen);
            if (connectionSocketArr[sockIdx] != INVALID_SOCKET)
            {
               //
               // Check id connection shall be accepted
               //
               if (!dataTablePtr->validateMasterIpAddr(inet_ntoa(peerAddr.sin_addr)))
               {
                  shutdown(connectionSocketArr[sockIdx], SD_BOTH);
                  closesocket(connectionSocketArr[sockIdx]);
                  connectionSocketArr[sockIdx] = INVALID_SOCKET;
                  TRACELOG2("Connection rejected on slot %d\n", sockIdx);
               }

               //
               // Set socket options (we ignore errors here, not critical)
               //
#ifdef TCP_NODELAY
               tcpOption = 1; // Enable option
               setsockopt(connectionSocketArr[sockIdx],
                          IPPROTO_TCP, TCP_NODELAY,
                          (char *) &tcpOption, sizeof (tcpOption));
#endif
#ifdef SO_SNDBUF
               tcpOption = MAX_MSG_SIZE;
               setsockopt(connectionSocketArr[sockIdx],
                          SOL_SOCKET, SO_SNDBUF,
                          (char *) &tcpOption, sizeof (tcpOption));
#endif
#ifdef SO_RCVBUF
               tcpOption = MAX_MSG_SIZE;
               setsockopt(connectionSocketArr[sockIdx],
                          SOL_SOCKET, SO_RCVBUF,
                          (char *) &tcpOption, sizeof (tcpOption));
#endif
#ifdef SO_LINGER
               tcpOption = 0; // Disable option = discard unsent data when closing
               setsockopt(connectionSocketArr[sockIdx],
                          SOL_SOCKET, SO_LINGER,
                          (char *) &tcpOption, sizeof (tcpOption));
#endif
               TRACELOG2("Connection accepted on slot %d\n", sockIdx);
            }
            break; // Leave for loop
         }
      }
   }

   //
   // Data received on socket
   //

   for (sockIdx = 0; sockIdx < MAX_CONNECTIONS; sockIdx++)
   {
      if (connectionSocketArr[sockIdx] != INVALID_SOCKET)
      {
         if (FD_ISSET (connectionSocketArr[sockIdx], &fdSet))
         {
            recvResult = recv (connectionSocketArr[sockIdx],
                               (char *) bufferArr, sizeof (bufferArr), 0);
            sendResult = 0;
            replyCnt = 0;

            //
            // Process client message
            //
            if (recvResult >= PREFIX_LEN) // Process only minimum message sizes
            {
               short dataLen;

               dataLen = (short) ((bufferArr[4] << 8) | (bufferArr[5] & 0xFF));
               // Validate length before processing message
               if ((dataLen + PREFIX_LEN) == recvResult)
               {
                  replyCnt = processMessage(&bufferArr[PREFIX_LEN],
                                            recvResult - PREFIX_LEN);

                  // The first two bytes (msg id) are returned untouched
                  bufferArr[2] = 0; // protocol identifier
                  bufferArr[3] = 0; // protocol identifier
                  bufferArr[4] = (char) ((replyCnt) >> 8);
                  bufferArr[5] = (char) ((replyCnt) & 0xFF);
                  sendResult = send(connectionSocketArr[sockIdx],
                                    (char *) bufferArr,
                                    replyCnt + PREFIX_LEN, 0);
               }
            }
            //
            // Check for disconnection and errors
            //
            if ((recvResult < PREFIX_LEN) ||
                (sendResult != replyCnt + PREFIX_LEN))
            {
               //
               // Free socket
               //
               shutdown(connectionSocketArr[sockIdx], SD_BOTH);
               closesocket(connectionSocketArr[sockIdx]);
               connectionSocketArr[sockIdx] = INVALID_SOCKET;
               if (recvResult == 0)
                  TRACELOG2("Disconnected slot %d nicely by other peer.\n",
                            sockIdx);
               else
                  TRACELOG2("Forced disconnection on slot %d!\n", sockIdx);
            }
         }
      }
   }
   return iReturnCode;
}

Will the below code resolve my problem? 下面的代码可以解决我的问题吗?

int ModbusTCPSlave::serverLoop()
{
   int iReturnCode = (FTALK_SUCCESS);
   int result;
   int sockIdx;
   int recvResult;
   int sendResult;
   fd_set fdSet;
   timeval timeVal;
   SOCKET maxFileDes;
   int replyCnt;
   int tcpOption;

   //if (!isStarted())
   //   return (FTALK_ILLEGAL_STATE_ERROR);

   //
   // Prepare file descriptor set for select call
   //
//   FD_ZERO (&fdSet);
//#ifdef _MSC_VER
//#  pragma warning(push)
//#  pragma warning(disable: 4127)
//#endif
//   FD_SET (listenSocket, &fdSet);
//#ifdef _MSC_VER
//#  pragma warning(pop)
//#endif
//   maxFileDes = listenSocket;
//   for (sockIdx = 0; sockIdx < MAX_CONNECTIONS; sockIdx++)
//  {
//      if (connectionSocketArr[sockIdx] != INVALID_SOCKET)
//#ifdef _MSC_VER
//#  pragma warning(push)
//#  pragma warning(disable: 4127)
//#endif
//         FD_SET (connectionSocketArr[sockIdx], &fdSet);
//#ifdef _MSC_VER
//#  pragma warning(pop)
//#endif
//      if (connectionSocketArr[sockIdx] > maxFileDes)
//         maxFileDes = connectionSocketArr[sockIdx];
//   }

   //
   // Block until accept request or received data or time-out
   //
   timeVal.tv_sec = (long) timeOut / 1000L;
   timeVal.tv_usec = ((long) timeOut % 1000L) * 1000L;
   if (timeOut == 0)
      result = select((int) maxFileDes + 1, &fdSet, NULL, NULL, NULL);
   else
      result = select((int) maxFileDes + 1, &fdSet, NULL, NULL, &timeVal);
//   if (result == SOCKET_ERROR)
//      return (FTALK_FILEDES_EXCEEDED);

   //
   // Check for time-out
   //
//   if (result == 0)
//   {
//      TRACELOG1("Slave poll time-out!\n");
//      dataTablePtr->timeOutHandler();
//
//    iReturnCode = (FTALK_REPLY_TIMEOUT_ERROR);
//   }

   //
   // Connection accept request
   //
 //  if (FD_ISSET (listenSocket, &fdSet))
   {
      // Search a free socket
 //     for (sockIdx = 0; sockIdx < MAX_CONNECTIONS; sockIdx++)
      {
  //       if (connectionSocketArr[sockIdx] == INVALID_SOCKET)
         {
            struct sockaddr_in peerAddr;
            SOCK_LEN_TYPE peerAddrLen = sizeof(peerAddr);

            // Yes, socket is free, try to accept a connection on it
            connectionSocketArr[sockIdx] = accept(listenSocket,
                                                  (struct sockaddr *) &peerAddr,
                                                  &peerAddrLen);
//           if (connectionSocketArr[sockIdx] != INVALID_SOCKET)
//           {
//               //
//               // Check id connection shall be accepted
//               //
//               if (!dataTablePtr->validateMasterIpAddr(inet_ntoa(peerAddr.sin_addr)))
//               {
//                  shutdown(connectionSocketArr[sockIdx], SD_BOTH);
//                  closesocket(connectionSocketArr[sockIdx]);
//                  connectionSocketArr[sockIdx] = INVALID_SOCKET;
//                  TRACELOG2("Connection rejected on slot %d\n", sockIdx);
//               }

               //
               // Set socket options (we ignore errors here, not critical)
               //
//#ifdef TCP_NODELAY
//               tcpOption = 1; // Enable option
//               setsockopt(connectionSocketArr[sockIdx],
//                          IPPROTO_TCP, TCP_NODELAY,
//                          (char *) &tcpOption, sizeof (tcpOption));
//#endif
//#ifdef SO_SNDBUF
//               tcpOption = MAX_MSG_SIZE;
//               setsockopt(connectionSocketArr[sockIdx],
//                          SOL_SOCKET, SO_SNDBUF,
//                          (char *) &tcpOption, sizeof (tcpOption));
//#endif
//#ifdef SO_RCVBUF
//               tcpOption = MAX_MSG_SIZE;
//               setsockopt(connectionSocketArr[sockIdx],
//                          SOL_SOCKET, SO_RCVBUF,
//                          (char *) &tcpOption, sizeof (tcpOption));
//#endif
//#ifdef SO_LINGER
//               tcpOption = 0; // Disable option = discard unsent data when closing
//               setsockopt(connectionSocketArr[sockIdx],
//                          SOL_SOCKET, SO_LINGER,
//                          (char *) &tcpOption, sizeof (tcpOption));
//#endif
//               TRACELOG2("Connection accepted on slot %d\n", sockIdx);
//            }
//           break; // Leave for loop
//         }
//      }
//   }

   //
   // Data received on socket
   //

//   for (sockIdx = 0; sockIdx < MAX_CONNECTIONS; sockIdx++)
//   {
//      if (connectionSocketArr[sockIdx] != INVALID_SOCKET)
//    {
//         if (FD_ISSET (connectionSocketArr[sockIdx], &fdSet))
//         {
            recvResult = recv (connectionSocketArr[sockIdx],
                               (char *) bufferArr, sizeof (bufferArr), 0);
            sendResult = 0;
            replyCnt = 0;

            //
            // Process client message
            //
            if (recvResult >= PREFIX_LEN) // Process only minimum message sizes
            {
               short dataLen;

               dataLen = (short) ((bufferArr[4] << 8) | (bufferArr[5] & 0xFF));
               // Validate length before processing message
               if ((dataLen + PREFIX_LEN) == recvResult)
               {
                  replyCnt = processMessage(&bufferArr[PREFIX_LEN],
                                            recvResult - PREFIX_LEN);

                  // The first two bytes (msg id) are returned untouched
                  bufferArr[2] = 0; // protocol identifier
                  bufferArr[3] = 0; // protocol identifier
                  bufferArr[4] = (char) ((replyCnt) >> 8);
                  bufferArr[5] = (char) ((replyCnt) & 0xFF);
                  sendResult = send(connectionSocketArr[sockIdx],
                                    (char *) bufferArr,
                                    replyCnt + PREFIX_LEN, 0);
               }
            }
            //
            // Check for disconnection and errors
            //
            if ((recvResult < PREFIX_LEN) ||
                (sendResult != replyCnt + PREFIX_LEN))
            {
               //
               // Free socket
               //
               shutdown(connectionSocketArr[sockIdx], SD_BOTH);
               closesocket(connectionSocketArr[sockIdx]);
               connectionSocketArr[sockIdx] = INVALID_SOCKET;
               if (recvResult == 0)
                  TRACELOG2("Disconnected slot %d nicely by other peer.\n",
                            sockIdx);
               else
                  TRACELOG2("Forced disconnection on slot %d!\n", sockIdx);
            }
//         }
//    }
//   }
   return iReturnCode;
}

Thanks Valter, You are right, I got it. 谢谢瓦尔特,你说得对,我明白了。 I've one more query in code there are two arrays regdata[30][65535]; 我在代码中又查询了两个数组regdata [30] [65535]; and bitarray[30][2000] after reading data from a file I can decide the first dimension of array ie [30]..if data in file is for two slave id then i require regdata[2][65535] and bitarray[2][2000]..how I can manage this assignment at runtime? 和bitarray [30] [2000]从文件中读取数据后,我可以确定数组的第一个维度,即[30] ..如果文件中的数据用于两个从属ID,则我需要regdata [2] [65535]和bitarray [ 2] [2000] ..如何在运行时管理此任务? I tried using vector like struct{ regdata[65535]; bitarray[2000]; }regstack; after reading file I 我尝试使用类似struct{ regdata[65535]; bitarray[2000]; }regstack; after reading file I struct{ regdata[65535]; bitarray[2000]; }regstack; after reading file I struct{ regdata[65535]; bitarray[2000]; }regstack; after reading file I tried to push_back() regstack, but it gives heap error..how I can resize this array in runtime? struct{ regdata[65535]; bitarray[2000]; }regstack; after reading file I尝试了push_back()regstack,但是它给出了堆错误。如何在运行时调整此数组的大小?

You can't have multiple sockets listening on the same port. 您不能在同一端口上监听多个套接字。 But if the address is validated inside processMessage couln't you simply change that function to accept requests for different slave IDs. 但是,如果在processMessage内验证了地址,则不会简单地更改该函数以接受对不同从属ID的请求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM