📄 modbusserver.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 + -