📄 modbusconnection.cpp
字号:
#include "StdAfx.h"
#include "ModbusConnection.h"
CONNECTION CModbusConnection::connections[MAX_CLIENTS];
HANDLE CModbusConnection::hFreeConnections;
CModbusConnection::CModbusConnection(void)
{
}
CModbusConnection::~CModbusConnection(void)
{
}
/*
* CreateConnections() function
*
* Initializes the client connections.
*/
void CModbusConnection::CreateConnections( void )
{
int i;
// Create semaphore used for maintaining free connection count
hFreeConnections = CreateSemaphore( NULL, // Security
0, // Initial count
MAX_CLIENTS, // Maximum count
NULL ); // Unnamed semaphore
// Initialize all connections
for( i = 0; i < MAX_CLIENTS; i++ )
{
// Init connection as "closed"
connections[i].ci.socket = 0;
// Create the 'stop signal' event object
connections[i].hStop = CreateEvent( NULL, // Security
TRUE, // Manual Reset
TRUE, // Initial state
NULL ); // Unnamed event
// Initialize critical section used to access the CONNINFO (ci) fields
InitializeCriticalSection( &connections[i].cs );
}
}
/*
* DeleteConnections() function
*
* Frees the variables/resources used by the client connections.
*/
void CModbusConnection::DeleteConnections( void )
{
int i;
// Cleanup
for( i = 0; i < MAX_CLIENTS; i++ )
{
DeleteCriticalSection( &connections[i].cs );
CloseHandle( connections[i].hStop );
}
CloseHandle( hFreeConnections );
}
/*
* EnableConnections() function
*
* Enables the client connections for usage.
*/
void CModbusConnection::EnableConnections( void )
{
int i;
// Release each connection and reset its 'stop signal'
for( i = 0; i < MAX_CLIENTS; i++ )
{
ResetEvent( connections[i].hStop );
ReleaseSemaphore( hFreeConnections, 1, NULL );
}
}
/*
* DisableConnections() function
*
* Closes all open connections. Calling thread will be
* blocked until all client handler threads terminate.
*/
void CModbusConnection::DisableConnections( void )
{
int i;
// Set 'stop signal' and wait for each connection to be released by client thread
for( i = 0; i < MAX_CLIENTS; i++ )
{
SetEvent( connections[i].hStop );
WaitForSingleObject( hFreeConnections, INFINITE );
}
}
/*
* OpenConnection() function
*
* Opens a client connection.
*
* Parameters
* [in] socket The socket ID to be assigned to the connection
* [in] lpSocketAddr Pointer to the socket address of the client
*
* Returns a handle to the opened connection, which a client thread can use
* to call other "Connection functions" on its connection.
*/
HANDLE CModbusConnection::OpenConnection( SOCKET socket, LPSOCKADDR_IN lpSocketAddr )
{
int i, idOldest;
DWORD dwEarliestLastTime;
BOOL fSockOpt;
LPCONNECTION lpConn = NULL;
// Disable Nagle algorithm for a Modbus server
fSockOpt = TRUE;
if( setsockopt( socket, IPPROTO_TCP, TCP_NODELAY, (char *) &fSockOpt, sizeof fSockOpt ) == SOCKET_ERROR )
{
CLogger::GetInstance()->Log(LOG_ERROR, _T("Unable to set TCP_NODELAY socket option"), WSAGetLastError() );
}
// Enable "Keep Alive" packets to be sent
fSockOpt = TRUE;
if( setsockopt( socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &fSockOpt, sizeof fSockOpt ) == SOCKET_ERROR )
{
CLogger::GetInstance()->Log(LOG_ERROR, _T("Unable to set SO_KEEPALIVE socket option"), WSAGetLastError() );
}
// Find first available (closed) connection
while( lpConn == NULL )
{
for( i = 0; i < MAX_CLIENTS && lpConn == NULL; i++ )
{
EnterCriticalSection( &connections[i].cs );
if( connections[i].ci.socket == 0 )
{
// "Closed" connection found -- take it
WaitForSingleObject( hFreeConnections, INFINITE );
// "Open" the connection
lpConn = &connections[i];
lpConn->ci.socket = socket;
// Convert client's socket address to IP dot-notation
sprintf( lpConn->ci.szAddr, "%s:%hu",
inet_ntoa( lpSocketAddr->sin_addr ),
htons( lpSocketAddr->sin_port ) );
// Set the time that this client connection was last used
lpConn->ci.dwLastTime = GetTickCount();
// Init statistics counters
lpConn->ci.dwRcvd = 0;
lpConn->ci.dwSent = 0;
lpConn->ci.dwGood = 0;
lpConn->ci.dwBad = 0;
// Enable the connection
ResetEvent( lpConn->hStop );
}
else
{
// Remember the oldest open connection
if( i == 0 || connections[i].ci.dwLastTime < dwEarliestLastTime )
{
dwEarliestLastTime = connections[i].ci.dwLastTime;
idOldest = i;
}
}
LeaveCriticalSection( &connections[i].cs );
}
if( lpConn == NULL )
{
// no connection available -- close oldest connection and try again
SetEvent( connections[idOldest].hStop );
WaitForSingleObject( hFreeConnections, INFINITE );
ReleaseSemaphore( hFreeConnections, 1, NULL );
}
}
// Notify console of the new connection
CLogger::GetInstance()->Log(LOG_INFO, _T("Connection accepted on socket"));
return (HANDLE) lpConn;
}
/*
* CloseConnection() function
*
* Closes a client connection.
*
* Parameters
* [in] hConn Handle of the connection to be closed.
*/
void CModbusConnection::CloseConnection( HANDLE hConn )
{
LPCONNECTION lpConn = (LPCONNECTION) hConn;
// Get socket to close and mark connection as closed
SOCKET socket;
EnterCriticalSection( &lpConn->cs );
socket = lpConn->ci.socket;
lpConn->ci.socket = 0;
LeaveCriticalSection( &lpConn->cs );
// Close the socket
if( closesocket( socket ) == SOCKET_ERROR )
{
CLogger::GetInstance()->Log(LOG_ERROR, _T("Unable to close socket"), WSAGetLastError());
}
else
{
CLogger::GetInstance()->Log(LOG_INFO, _T("Socket closed"));
}
// Release the connection for re-use
ReleaseSemaphore( hFreeConnections, 1, NULL );
}
/*
* IncrementConnCounters() function
*
* Updates the statistics for a client connection
* with the results of a client transaction.
*
* Parameters
* [in] hConn Handle of the connection to be updated
* [in] fGoodRequest Set TRUE if sent a positive response to client
* [in] wRcvd Number of bytes received from client for the transaction
* [in] wSent Number of bytes sent to client for the transaction
*/
void CModbusConnection::IncrementConnCounters( HANDLE hConn, BOOL fGoodRequest, WORD wRcvd, WORD wSent )
{
LPCONNECTION lpConn = (LPCONNECTION) hConn;
EnterCriticalSection( &lpConn->cs );
// Set the time that this client connection was last used
lpConn->ci.dwLastTime = GetTickCount();
// Increment the request counter for either 'good' or 'bad' requests
if( fGoodRequest ) lpConn->ci.dwGood++; else lpConn->ci.dwBad++;
// Update byte counters
lpConn->ci.dwRcvd += wRcvd;
lpConn->ci.dwSent += wSent;
LeaveCriticalSection( &lpConn->cs );
}
/*
* GetConnInfo() function
*
* Retrieves the latest statistics for a client connection.
*
* Parameters
* [in] hConn Handle of the connection to get statistics
* [out] lpInfo Pointer to a CONNINFO struct for receiving the statistics
*/
void CModbusConnection::GetConnInfo( INT idConn, LPCONNINFO lpInfo )
{
LPCONNECTION lpConn = &connections[idConn];
EnterCriticalSection( &lpConn->cs );
*lpInfo = lpConn->ci;
LeaveCriticalSection( &lpConn->cs );
}
/*
* GetConnSocket() function
*
* Retrieves the socket ID for a client connection.
*
* Parameters
* [in] hConn Handle of the connection to get the socket ID
*
* Returns the socket ID for the connection.
*/
SOCKET CModbusConnection::GetConnSocket( HANDLE hConn )
{
LPCONNECTION lpConn = (LPCONNECTION) hConn;
return lpConn->ci.socket;
}
/*
* GetConnStopEvent() function
*
* Retrieves the handle of the 'Stop' event object for a client connection.
*
* Parameters
* [in] hConn Handle of the connection to get the 'Stop' event
*
* Returns the handle of the connection's 'Stop' event object
*/
HANDLE CModbusConnection::GetConnStopEvent( HANDLE hConn )
{
LPCONNECTION lpConn = (LPCONNECTION) hConn;
return lpConn->hStop;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -