2014-02-06 93 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以便能夠處理不同目標的消息。 –