Я работаю над клиентским сервером 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, но это дает кучу ошибок .. как я могу изменить размер этого массива во время выполнения?
Вы не можете прослушивать несколько сокетов на одном и том же порту. Но если адрес проверяется внутри processMessage, вы не можете просто изменить эту функцию, чтобы принимать запросы на разные идентификаторы ведомых устройств.
Других решений пока нет …