📄 tcpip.cpp
字号:
// @doc
//
// @module TcpIp.cpp | TcpIp class constructors/destructors
//
// This module contains the the constructor/destructors for the TcpIp
// class along with the Connect and Close member functions
//
// Maintenance:
//
// Version Date Who What
// ------- ----------- ------ -------------------------------------
// 7.0 04/24/97 blm Created
// 7.1 02/20/98 mvs Modified it for Tcp server support
// 7.1 05/20/98 mvs Added UDP Support
//
#include <afx.h>
#include <WinSock2.h>
#include <ItkErr.h>
#include <TcpIp.h>
#define IO_INVALID_ADDRESS 0xFFFF
#define SERVER_ACPT_TIMEOUT 100
#define SERVER_RECV_TIMEOUT 5
#define SERVER_NO_RECV_TIMEOUT 200
#define SERVER_SHUT_TIMEOUT 3000
#define SERVER_SHUT_RETRY_TIMEOUT 1000
extern "C" {
EXPORT32 BOOL WINAPI DllMain( HANDLE hInstance, DWORD dwReason, VOID *pReserved )
{
BOOL bSuccess = 1;
int nReturnVal;
switch ( dwReason )
{
case DLL_PROCESS_ATTACH:
{
WORD wVerReq;
WSADATA sWsdata;
wVerReq = MAKEWORD(2,2);
nReturnVal = WSAStartup(wVerReq, &sWsdata);
if (nReturnVal)
{
// LogError here ?
}
break;
}
case DLL_PROCESS_DETACH:
nReturnVal = WSACleanup();
if (nReturnVal)
{
// LogError here
}
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
default:
break;
}
return( bSuccess );
pReserved = pReserved;
} // End of DllMAin()
} // Extern "C"
//
//
// @mfunc <c CTcpIp> constructor for this class. This function
// simply initializes all the data members,
// initializes a critical section used throughout
// the object and
//
//
// @parm IN const TCHAR * | pszAppName | Name of the driver that is using the object
//
// @parm IN const TCHAR * | szIpAddress| Ip AddressName of the device to be connected
//
// @parm IN const BOOL | bClient | The object to be initialized in Client Mode
// or Server Mode. TRUE=Client, FALSE=Server
// In Client mode - this object initiates the
// the connection request
// In Server mode - this object waits for
// a client to initiate the connection request
//
// @parm IN const BOOL | bTcp | The object to be initialized using
// Tcp or Udp protocol. TRUE=Tcp, FALSE=Udp
//
// @parm IN void | CALLBACK *lpfnRcvCallback | Callback Function supplied by the caller to
// allow the CTcpIp object to return back the data
// in client mode
// received from an non-blocking asynchronous recv call.
// function will just display the message.
// The prototype of the completion routine is as follows:
//
// void CALLBACK CompletionROUTINE(
// IN DWORD dwError,
// IN DWORD cbTransferred,
// IN LPWSAOVERLAPPEDlpOverlapped,
// IN DWORD dwFlags
// );
//
// @parm IN void*| pCallbackParam | Callback Parameter which is used
// by the receive Callback function
//
// @parm IN OPTIONAL void | lpfnMsgDisplay | Function supplied by the caller to
// allow the CTcpIp object to report
// events. By default, its assumed that this
// function will just display the message.
//
// @parm IN OPTIONAL void | CALLBACK *lpfnTcpServerCallback | Callback Function supplied by the caller to
// allow the CTcpIp object in server mode
// to send back the data received from a client
//
// @parm IN OPTIONAL void | CALLBACK *lpfnUdpServerCallback | Callback Function supplied by the caller to
// allow the CTcpIp object in server mode
// to send back the data received from a client
//
// @parm IN OPTIONAL unsigned short int| uListenPortNumber | The Port Number for listening for
// a connection.(needed only when
// object is instanciated in server mode).
//
// @parm IN OUT OPTIONAL unsigned char* | pServerBuf | Buffer for storing data received from a
// client (needed only when object is
// instanciated in server mode).
//
// @parm IN OPTIONAL DWORD | dwBufSize | Size of Buffer for storing data received from a
// client (needed only when object is
// instanciated in server mode).
//
EXPORT32 CTcpIp::CTcpIp(IN const TCHAR *szAppName,
IN const TCHAR *szIpAddress,
IN const BOOL bClient,
IN const BOOL bTcp,
IN void (CALLBACK *lpfnRcvCallback)(DWORD dwError, DWORD dwTransferred,
LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags),
IN void *pCallbackParam,
IN OPTIONAL void (*lpfnMsgDisplay)(const TCHAR *szString),
IN OPTIONAL void (CALLBACK *lpfnTcpServerCallback)(void *pCallbackParam, SOCKET ClientSocket, DWORD dwActualSize),
IN OPTIONAL void (CALLBACK *lpfnUdpServerCallback)(void *pCallbackParam, SOCKADDR ClientSockaddr, DWORD dwActualSize),
IN OPTIONAL const unsigned short int uListenPortNumber,
IN OUT OPTIONAL unsigned char *pServerBuf,
IN OPTIONAL DWORD dwBufSize)
{
//
// Check if application is a client or server, Tcp or Udp
//
m_bClient = bClient;
m_bTcp = bTcp;
memset((void *)&m_WriteOverlapped, 0, sizeof(OVERLAPPED));
memset((void *)&m_ReadOverlapped, 0, sizeof(OVERLAPPED));
memset((void *)&m_sSocketAddress, 0, sizeof(SOCKADDR));
memset((void *)&m_sRemoteAddress, 0, sizeof(SOCKADDR));
// Save the callback parameter
m_ReadOverlapped.hEvent = (HANDLE)pCallbackParam;
strcpy(m_szAppName, szAppName);
strcpy(m_szIpAddress, szIpAddress);
m_lpfnMsgDisplay = lpfnMsgDisplay;
m_lpfnRcvCallback = lpfnRcvCallback;
m_nSocketAddressSize = sizeof(SOCKADDR);
m_nRemoteAddressSize = sizeof(SOCKADDR);
if (m_bClient)
{
// This is a client. Process accordingly
DWORD dwError;
struct hostent *hp = NULL;
unsigned long lIpAddress = 0;
m_lIpAddress = INADDR_NONE;
m_uPortNumber = 0;
m_Socket = INVALID_SOCKET;
m_sHost = NULL;
m_bStop = FALSE;
m_dwConnectState = DRV_NOT_CONNECTED;
m_bSocketState = SOCKET_NOT_CREATED;
m_dwStatus = IO_CREATE_SOCKET;
m_dwReadThreadId = 0;
m_hReadThread = (HANDLE)NULL;
//
// Convert the Ip address to a 32-bit integer value
//
lIpAddress = GetAddr(szIpAddress);
if (INADDR_NONE != lIpAddress)
{
m_dwStatus = IO_SUCCESS;
m_lIpAddress = lIpAddress;
dwError = Open();
if (IO_SUCCESS != dwError)
{
//
// Error in Creating Socket
//
m_dwStatus = dwError;
}
}
else
{
m_dwStatus = IO_INVALID_ADDRESS;
}
}// End of if(bClient) loop
else
{
// This is a server. Process accordingly
// Set the stop flag and signal the event for the threads
m_bStop = FALSE;
m_Socket = INVALID_SOCKET;
m_bSocketState = SOCKET_NOT_CREATED;
m_dwConnectState = DRV_NOT_CONNECTED;
m_dwListenThreadId = 0;
m_hListenThread = (HANDLE)NULL;
m_uPortNumber = uListenPortNumber;
m_lpfnTcpServerCallback = lpfnTcpServerCallback;
m_lpfnUdpServerCallback = lpfnUdpServerCallback;
m_pServerBuf = pServerBuf;
m_dwServerBufSize = dwBufSize;
m_pCallbackParam = (HANDLE)pCallbackParam;
// Initialize the Critical section
InitializeCriticalSection(&m_hConnectionListCS);
if (uListenPortNumber)
{
m_hListenThread = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)ListenHandler,
(LPVOID)this,
0,
&m_dwListenThreadId);
}
}// End of else-if(bClient) loop
}
//
// @mfunc <c CTcpIp> destructor. Calls the Close member function
// to take care of cleaning up resources created by the Open
// member function, then frees the resources created by the
// constructor.
//
EXPORT32 CTcpIp::~CTcpIp()
{
if (m_bClient)
{
Close();
}
else
{
m_bStop = TRUE;
DWORD dwErrorCode = IO_SUCCESS, lpExitCode = 0;
BOOL bRet = FALSE;
int nError = 0;
int nCounter = 0;
Sleep(SERVER_SHUT_TIMEOUT);
nCounter = 0;
while ((this->m_bSocketState == SOCKET_CLOSING) && (nCounter < MAX_WAIT_COUNT))
{
Sleep(SERVER_SHUT_RETRY_TIMEOUT);
nCounter++;
}
if (m_hListenThread != (HANDLE) NULL)
{
bRet = GetExitCodeThread(m_hListenThread, &lpExitCode);
if (bRet)
{
if (lpExitCode == STILL_ACTIVE)
{
TerminateThread(m_hListenThread, 0);
}
}
else
{
TerminateThread(m_hListenThread, 0);
}
}
if (m_hReceiveThread != (HANDLE) NULL)
{
bRet = GetExitCodeThread(m_hReceiveThread, &lpExitCode);
if (bRet)
{
if (lpExitCode == STILL_ACTIVE)
{
TerminateThread(m_hReceiveThread, 0);
}
}
else
{
TerminateThread(m_hReceiveThread, 0);
}
}
CloseAllConnections();
CloseHandle(m_hListenThread);
CloseHandle(m_hReceiveThread);
DeleteCriticalSection(&m_hConnectionListCS);
}
}
//
//
// FUNCTION: Open
//
// TcpIp Client Mode
// This function creates the socket for the TCP client and
// sets the proper modes for the socket
//
// Return Value: IO_SUCESS - If successful
// IO_CLIENT_ERR - If object not in client mode
// IO_CREATE_SOCKET - If error creating a socket
//
DWORD CTcpIp::Open()
{
DWORD dwErrorCode = IO_SUCCESS;
// This is a client not server. Just go away.
if (!this->m_bClient)
{
dwErrorCode = IO_CLIENT_ERR;
return(dwErrorCode);
}
if (this->m_Socket != INVALID_SOCKET)
{
if (this->m_bSocketState == SOCKET_CREATED)
{
return(dwErrorCode);
}
else
{
TRACE("TCP: Failed to create a new socket\n");
Close();
}
}
//
// Create Socket. By default it is in Blocking Mode
//
if (m_bTcp)
{
this->m_Socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
}
else
{
this->m_Socket = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED);
}
if (INVALID_SOCKET == this->m_Socket)
{
dwErrorCode = IO_CREATE_SOCKET;
this->m_bSocketState = SOCKET_CLOSED;
m_Socket = INVALID_SOCKET;
TRACE("TCP: Open- WSASocket() failed to create a new socket, Error = %d\n",WSAGetLastError());
}
else
{
int opt_val = 1,
nError,
nTxBufSize = TCP_INPUT_QUEUE_SIZE,
nRxBufSize = TCP_OUTPUT_QUEUE_SIZE;
nError = setsockopt(this->m_Socket, SOL_SOCKET, SO_DONTLINGER, (char *)&opt_val, sizeof(opt_val));
if (m_bTcp)
{
nError = setsockopt(this->m_Socket, IPPROTO_TCP, TCP_NODELAY, (char *)&opt_val, sizeof(opt_val)) ;
}
this->m_bSocketState = SOCKET_CREATED;
TRACE("TCP: New socket created\n");
}
return(dwErrorCode);
}
//
// @mfunc Close - In TcpIp Client Mode
// This function frees all the resources created by the
// Open member function. This primarily consists of shutdown
// for connected socket, internal buffers and events.
// It also is responsible for
// stopping the asynchronous read thread if one exists.
//
// @parm None |
//
// @rvalue IO_SUCCESS | If successful
//
// @rvalue IO_CLIENT_ERR | If object not in client mode
//
EXPORT32 DWORD CTcpIp::Close(void)
{
DWORD dwErrorCode = IO_SUCCESS, lpExitCode = 0;
BOOL bRet = FALSE;
int nError = 0;
// This is a client not server. Just go away.
if (!this->m_bClient)
{
dwErrorCode = IO_CLIENT_ERR;
return(dwErrorCode);
}
if (m_hReadThread != (HANDLE) NULL)
{
bRet = GetExitCodeThread(m_hReadThread, &lpExitCode);
if (bRet)
{
if (lpExitCode == STILL_ACTIVE)
{
TerminateThread(m_hReadThread, 0);
}
}
else
{
TerminateThread(m_hReadThread, 0);
}
CloseHandle(m_hReadThread);
m_hReadThread = (HANDLE) NULL;
}
//
// If Socket not created or already closed; then just return
//
if (m_Socket == INVALID_SOCKET)
{
this->m_bSocketState = SOCKET_CLOSED;
return(dwErrorCode);
}
//
// Close connection to this socket.
//
this->DisConnect();
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -