C++ 具有多个从属id的modbus tcp客户端服务器

C++ 具有多个从属id的modbus tcp客户端服务器,c++,tcp,windows-ce,modbus,C++,Tcp,Windows Ce,Modbus,我在win ce 6 modbus tcp客户机服务器上工作,该应用程序是为客户机-服务器通信开发的,工作正常。现在req是我的从设备,它应该响应主/客户机轮询的不同从地址。我可以只更改从属id并建立连接,还是需要关闭以前的连接并再次建立新的连接 下面是代码,它在一个节点上运行良好,如果我用另一个节点ID进行轮询,那么它会给出异常。什么改变了它需要与其他节点同时通信。我的设备应该能够与modbus tcp上的32个diff节点通信。我应该为每个节点创建单独的线程,但它们将如何在同一端口上通信?在

我在win ce 6 modbus tcp客户机服务器上工作,该应用程序是为客户机-服务器通信开发的,工作正常。现在req是我的从设备,它应该响应主/客户机轮询的不同从地址。我可以只更改从属id并建立连接,还是需要关闭以前的连接并再次建立新的连接

下面是代码,它在一个节点上运行良好,如果我用另一个节点ID进行轮询,那么它会给出异常。什么改变了它需要与其他节点同时通信。我的设备应该能够与modbus tcp上的32个diff节点通信。我应该为每个节点创建单独的线程,但它们将如何在同一端口上通信?在与其他节点建立连接之前,是否关闭上一个节点

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;
}
startupServer(int slaveAddr,const TCHAR*const主机名)
{
int结果;
国际人口;
主机地址中的结构sockaddr_;
如果(isStarted())
返回(FTALK_非法_状态_错误);
//注意:对于TCP,我们允许0作为从属地址,-1表示忽略从属地址
如果((slaveAddr<-1)| |(slaveAddr>255))
返回(FTALK_非法_参数_错误);
这->slaveAddr=slaveAddr;
//
//针对Win32平台的特殊处理,需要加载WinSock DLL
//
#ifdef_WINSOCKAPI_
WSADATA WSADATA;
结果=WSAStartup(0x0101和wsaData);
如果(结果!=0)
返回(FTALK_套接字_LIB_错误);
#恩迪夫
//
//开放式插座
//
listenSocket=socket(PF_INET,SOCK_STREAM,0);
if(listenSocket==无效的_套接字)
{
shutdownServer();
返回(FTALK\U OPEN\U ERR);
}
//
//配置侦听套接字选项(此处忽略错误)
//
#如果定义为SO_REUSEADDR
tcpOption=1;//启用选项
setsockopt(listenSocket、SOL_SOCKET、SO_REUSEADDR、,
(char*)和tcpOption,sizeof(tcpOption));
#恩迪夫
//
//将侦听套接字绑定到端口
//
hostAddress.sin_family=AF_INET;
如果((主机名==NULL)| |(主机名[0]=='\0'))
hostAddress.sin_addr.s_addr=htonl(INADDR_ANY);
其他的
{
hostAddress.sin\u addr.s\u addr=inet\u addr((char*)主机名);
#if!defined(_VXWORKS__)//我们不支持用VXWORKS解析主机名
if(hostAddress.sin\u addr.s\u addr==INADDR\u NONE)
{
结构主机*主机信息;
hostInfo=gethostbyname((char*)主机名);
if(hostInfo==NULL)
返回(FTALK\U TCPIP\U CONNECT\U ERR);
hostAddress.sin_addr=*(结构在_addr*)hostInfo->h_addr;
}
#恩迪夫
}
hostAddress.sin_port=htons(端口号);
结果=绑定(listenSocket,(struct sockaddr*)和主机地址,
sizeof(主机地址));
如果(结果==套接字错误)
{
shutdownServer();
开关(socketerno)
{
#ifdef_WINSOCKAPI_
案例WSAEACCESS:
返回(FTALK\u端口\u无访问权);
案例WSAEADDRINUSE:
返回(FTALK\u端口\u已绑定);
案例WSAEADDRNOTAVAIL:
违约:
返回(FTALK\u端口\u无效);
#否则
案例ENOTCONN://Linux 7.2报告此错误如果没有根权限
个案:
返回(FTALK\u端口\u无访问权);
使用情况:
返回(FTALK\u端口\u已绑定);
案例EADDRNOTAVAIL:
违约:
返回(FTALK\u端口\u无效);
#恩迪夫
}
}
//
//开始监听传入的连接
//
结果=侦听(listenSocket,
((最大连接数maxFileDes)
maxFileDes=连接socketar[sockIdx];
}
//
//阻止,直到接受请求或接收到数据或超时
//
timeVal.tv_sec=(长)超时/1000L;
timeVal.tv_usec=((长)超时%1000L)*1000L;
如果(超时==0)
结果=选择((int)maxFileDes+1,&fdSet,NULL,NULL,NULL);
其他的
结果=选择((int)maxFileDes+1,&fdSet,NULL,NULL,&timeVal);
如果(结果==套接字错误)
返回(超过FTALK\u文件定义);
//
//检查是否超时
//
如果(结果==0)
{
TRACELOG1(“从属轮询超时!\n”);
dataTablePtr->timeOutHandler();
iReturnCode=(FTALK\u应答\u超时\u错误);
}
//
//连接接受请求
//
if(FD_ISSET(listenSocket和fdSet))
{
//搜索一个空闲的套接字
对于(sockIdx=0;sockIdxint 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;
}