2014-02-06 115 views
0

我正在使用win ce 6 modbus tcp客户端服务器,应用程序是为客户端服务器通信而开发的,并且工作正常。现在req是我的从属设备应该响应由主/客户端轮询的差分从地址。我可以只更改从属身份和建立连接,或者我需要关闭以前的连接,并再次建立新的连接modbus tcp clent服务器与多个从服务器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; 
} 

下面的代码能解决我的问题吗?

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

谢谢Valter,你说得对,我明白了。我在代码中有一个查询有两个数组regdata [30] [65535];和bitarray [30] [2000]从文件中读取数据后,我可以决定数组的第一维,即[30] ..如果文件中的数据是用于两个从机ID,那么我需要regdata [2] [65535]和bitarray [ 2] [2000] ..我如何在运行时管理这个任务?我试图使用向量像struct{ regdata[65535]; bitarray[2000]; }regstack; after reading file I试图push_back()regstack,但它给堆错误..我可以在运行时调整这个数组?

+0

我可以coomunicate在相同的端口和IP地址的diff节点? – user1586695

+0

可以任何帮助我 – user1586695

+0

Modbus TCP专家请hepl – user1586695

回答

1

您不能在同一个端口上侦听多个套接字。但是,如果地址在processMessage内部进行了验证,那么您只需更改该函数以接受针对不同从属标识的请求。

+0

您可以请解释..或编辑上述代码,因为我是新的C++和MODBUS TCP – user1586695

+0

我应该在processMessage中调用accept函数吗? – user1586695

+0

在Modbus TCP/IP数据以数据包形式组织,就像它在串行链路上的“传统”Modbus实现中发生的一样。在数据包中有一个字段(1字节的IIRC),用于标识消息的接收者。我想processMessage函数(在您的代码中实现)检查特定的ID并相应地处理请求(读取/写入modbus regs)。要在同一IP地址上支持多个“虚拟”设备,您不应更改网络代码(您发布的代码),而应更改processMessage以便能够处理不同目标的消息。 –