⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 modbusconnection.cpp

📁 Convert Interface on a embedded System
💻 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 + -