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

📄 modbusserver.cpp

📁 Convert Interface on a embedded System
💻 CPP
字号:
#include "StdAfx.h"
#include "ModbusServer.h"

// Forward declarations
UINT ListenThread( LPVOID lpParam );

INT CALLBACK CheckAccept( LPWSABUF lpCallerId, 
						  LPWSABUF lpCallerData, 
						  LPQOS    lpSQOS, 
						  LPQOS    lpGQOS, 
						  LPWSABUF lpCalleeId, 
						  LPWSABUF lpCalleeData, 
						  GROUP *  g, 
						  DWORD    dwCallbackData );

CModbusServer::CModbusServer(void)
{
	CModbusConnection::CreateConnections();
	CreateServer();
}

CModbusServer::~CModbusServer(void)
{
	CModbusConnection::DeleteConnections();
}

/*
 *	CreateServer() function
 *
 *	Initializes variables/resources used by the server (listening thread).
 */
void CModbusServer::CreateServer( void )
{
	// Create the 'server stopped' event object
	hStopped = CreateEvent( NULL,	// Security
							TRUE,	// Manual Reset
							TRUE,	// Initial state
							NULL );	// Unnamed event
}


/*
 *	DeleteServer() function
 *
 *	Frees variables/resources used by the server (listening thread).
 */
void CModbusServer::DeleteServer( void )
{
	CloseHandle( hStopped );
}


/*
 *	IsServerRunning() function
 *
 *	Returns TRUE if server (listening thread) is running; 
 *	otherwise, returns FALSE.
 */
BOOL CModbusServer::IsServerRunning( void )
{
	// If 'server stopped' event is not set (timeout), server is running
	return (WaitForSingleObject( hStopped, 0 ) == WAIT_TIMEOUT);
}


/*
 *	StartServer() function
 *
 *	Attempts to start the server listening thread,
 *	if server not already running.
 */
void CModbusServer::StartServer( void )
{
	SOCKADDR_IN saServer;
	HANDLE		hListenThread;
	DWORD       dwThreadAddr;

	// Check for server already running
	if( IsServerRunning() )
		return;

	// Create a TCP/IP stream socket
	listenSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
	if( listenSocket == INVALID_SOCKET )
	{
		CLogger::GetInstance()->Log(LOG_ERROR, _T("Unable to create listen socket"), WSAGetLastError() );
		return;
	}

	// Fill in the address structure
	saServer.sin_family = AF_INET;
	saServer.sin_addr.s_addr = INADDR_ANY;
	saServer.sin_port = htons( 502 );

	// Bind our name to the socket
	if( bind( listenSocket, (LPSOCKADDR) &saServer, sizeof saServer ) == SOCKET_ERROR )
	{
		CLogger::GetInstance()->Log(LOG_ERROR, _T("Unable to bind listen socket"), WSAGetLastError() );
		closesocket( listenSocket );
		return;
	}

	// Set the socket to listen
	if( listen( listenSocket, SOMAXCONN ) == SOCKET_ERROR )
	{
		CLogger::GetInstance()->Log(LOG_ERROR, _T("Unable to listen on socket"), WSAGetLastError() );
		closesocket( listenSocket );
		return;
	}

	// Create the listening thread
	//hListenThread = CreateThread( NULL,            // Security
	//					          0,		       // Stack size
	//					          ListenThread,    // Function address
	//					          NULL,  	       // Argument
	//					          0,		       // Init flag
	//					          &dwThreadAddr);  // Thread address

	hListenThread = AfxBeginThread(ListenThread, (LPVOID)this);
	if( hListenThread == NULL )
	{
		CLogger::GetInstance()->Log(LOG_ERROR, _T("Unable to create listening thread"), GetLastError() );
		closesocket( listenSocket );
	}
	else
	{
		// Won't be using the thread handle, so close it now. (Thread will continue to run)
		CloseHandle( hListenThread );
	}
}


/*
 *	StopServer() function
 *
 *	Stops the server (listening thread), if server is running.
 */
void CModbusServer::StopServer( void )
{
	// Close listening socket to stop server
	if( IsServerRunning() )
	{
		closesocket( listenSocket );
	}
}


/*
 *	JoinServer() function
 *
 *	Causes the calling thread to be blocked until the server
 *	(listening thread) signals it termination.
 */
void CModbusServer::JoinServer( void )
{
	// Wait until server stops
	WaitForSingleObject( hStopped, INFINITE );
}

void CModbusServer::StartClientThread( SOCKET socket, LPSOCKADDR_IN lpSocketAddr )
{
	HANDLE hConn = CModbusConnection::OpenConnection(socket, lpSocketAddr);

	m_modbusClient.StartClientThread(hConn);

}

/*
 *	ListenThread() callback function
 *
 *	Called as the listening thread for the server.
 */
UINT ListenThread( LPVOID lpParam )
{
	CModbusServer* _this = (CModbusServer*)lpParam;

    SOCKET		socket;
	SOCKADDR_IN	saClient;
    int         lenSockAddr = sizeof saClient;
	int         idError;

	// Reset the 'server stopped' event to indicate that server running
	ResetEvent( _this->hStopped );

    // Display server startup message
//    _this->LogServerStartup();

	// Make all connections available
	CModbusConnection::EnableConnections();

	// Loop forever accepting connections (blocking on accept).
	while( TRUE )
	{
	    socket = WSAAccept( _this->listenSocket, (LPSOCKADDR) &saClient, &lenSockAddr, CheckAccept, 0 );
		if( socket == INVALID_SOCKET )
		{
			idError = WSAGetLastError();
			if( idError == WSAECONNREFUSED )
			{
				// Connection refused by CheckAccept()
				// Should never get here since CheckAccept() accepts all clients
				continue;
			}

			// Unable to accept more clients -- stop server
			if( idError != WSAEINTR )
			{
				// Treat as error if not WSAEINTR, which indicates normal stop by StopServer()
				CLogger::GetInstance()->Log(LOG_ERROR, _T("Listen thread terminated abnormally"), idError );
				closesocket( _this->listenSocket );
			}

			break;
		}
	
		// Accepted client connection
		_this->StartClientThread(socket, &saClient);
	}


	// Wait for all clients to stop
	CModbusConnection::DisableConnections();

    // Display server shutdown message
//	_this->LogEvent( "Modbus Server stopped" );

	// Set the 'server stopped' event to indicate that server stopped
	SetEvent( _this->hStopped );
	return 0;
}


/*
 *	CheckAccept() callback function
 *
 *	Called as the 'Condition Function" for WSAAccept().
 *
 *	This sample server does not implement any Access Control,
 *	and simply returns CF_ACCEPT for any client connection request.
 *
 *	If it was desired to implement Access Control,
 *	then one could use the info passed to this function
 *	to determine if a client should be accepted and 
 *	return CF_REJECT if client was not authorized.
 */
INT CALLBACK CheckAccept( LPWSABUF lpCallerId, 
						  LPWSABUF lpCallerData, 
						  LPQOS    lpSQOS, 
						  LPQOS    lpGQOS, 
						  LPWSABUF lpCalleeId, 
						  LPWSABUF lpCalleeData, 
						  GROUP *  g, 
						  DWORD    dwCallbackData )
{
	return CF_ACCEPT;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -