tcp клиентский сервер Modbus с несколькими подчиненными идентификаторами

Я работаю над клиентским сервером win ce 6 modbus tcp, приложение разработано для взаимодействия клиент-сервер и работает нормально. Теперь req — мое ведомое устройство должно отвечать на адреса diff slave, опрошенные master / client. Могу ли я просто изменить ведомый идентификатор и установить соединение или мне нужно закрыть предыдущее соединение и снова установить новое

Ниже приведен код, который работает нормально для одного узла, если я опрашивал с другим идентификатором узла, то это дает исключение. Что бы изменить его, необходимо связаться с другим узлом одновременно. Мое устройство должно поддерживать связь с 32 узлами diff по протоколу Modbus TCP. Должен ли я создавать отдельные потоки для каждого узла, но как они будут взаимодействовать на одном и том же порту? перед установлением соединения с другим узлом я должен закрыть предыдущий узел?

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

Спасибо Вальтер, ты прав, я понял. У меня есть еще один запрос в коде, есть два массива regdata [30] [65535]; и bitarray [30] [2000] после чтения данных из файла я могу определить первое измерение массива, т.е. [30] .. если данные в файле для двух идентификаторов ведомых, то мне требуются regdata [2] [65535] и bitarray [ 2] [2000] .. как я могу управлять этим назначением во время выполнения? Я пробовал использовать вектор как struct{ regdata[65535]; bitarray[2000]; }regstack; after reading file I попытался push_back () regstack, но это дает кучу ошибок .. как я могу изменить размер этого массива во время выполнения?

0

Решение

Вы не можете прослушивать несколько сокетов на одном и том же порту. Но если адрес проверяется внутри processMessage, вы не можете просто изменить эту функцию, чтобы принимать запросы на разные идентификаторы ведомых устройств.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]