I'm working on win ce 6 modbus tcp client server, application is developed for a client server communication and it is working fine. now req is my slave device should respond to the diff slave addresses polled by master/client. Can I just change slave id and establish connection or I need to close previous connection and again establish new one
below is the code, which is working fine for one node, if I polled with other node ID then it gives exception. what change it req to communicate with other node simultaneously. My device should be able to communicate with 32 diff nodes on modbus tcp. Shall I create individual threads for each node but how they will communicate on same port? before establishing connection with other node shall I close previous node?
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;
}
Will the below code resolve my problem?
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;
}
Thanks Valter, You are right, I got it. I've one more query in code there are two arrays regdata[30][65535]; and bitarray[30][2000] after reading data from a file I can decide the first dimension of array i.e. [30]..if data in file is for two slave id then i require regdata[2][65535] and bitarray[2][2000]..how I can manage this assignment at runtime? I tried using vector like struct{ regdata[65535]; bitarray[2000]; }regstack; after reading file I
tried to push_back() regstack, but it gives heap error..how I can resize this array in runtime?
You can't have multiple sockets listening on the same port. But if the address is validated inside processMessage couln't you simply change that function to accept requests for different slave IDs.