c***@gmail.com
2013-07-05 13:29:26 UTC
I found an interesting solution of that issue.
First of all:
YES its possible to use CAsyncSocket with full features without a CWin Window.
NO its no common Console App.
And it works fine :-)
You need a CWorker Class derived from CWinApp, because CWinApp:CWinThread has the MFC-Message-Loop Run().
class CWorkerApp :public CWinApp;
Second you need your CAsync Class derived from CAsyncSocket, to override the virtual Callbacks.
class CAsync :public CAsyncSocket;
Third you must tell CWinApp tu run without a CWin-Dialog, because default it stops, if it has no Window.
AfxOleSetUserCtrl(FALSE);
Keep in mind, you have no UI to that App. You just see it under Processes in Task-Manager and you can Kill it only that way.
But the good message, you can allocate a Console Window to put your DEBUG output there.
The rest I found in MSDN dokumentation, Sample EchoServer, and "of course" in Internet :))
I post the full source afterwards. They consist of
MyEchoSocket.h
EchoServer.h
MyEchoSocket.cpp
EchoServer.cpp
// MyEchoSocket.h : header file
//
#if !defined(AFX_MYECHOSOCKET_H__166D4120_2F94_4231_AE60_7C719E3EC05C__INCLUDED_)
#define AFX_MYECHOSOCKET_H__166D4120_2F94_4231_AE60_7C719E3EC05C__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class MyEchoSocket : public CAsyncSocket
{
public:
//my Overwrites of the Callbacks of the Socket-Events, I hook on by Create
virtual void OnReceive(int nErrorCode); //FD_READ
virtual void OnSend(int nErrorCode); //FD_WRITE
virtual void OnOutOfBandData(int nErrorCode); //FD_OOB
virtual void OnAccept(int nErrorCode); //FD_ACCEPT
virtual void OnConnect(int nErrorCode); //FD_CONNECT
virtual void OnClose(int nErrorCode); //FD_CLOSE
BOOL Create(
UINT nSocketPort = 0,
int nSocketType = SOCK_STREAM,
long lEvent = FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE,
LPCTSTR lpszSocketAddress = NULL
);
void SetParentApp(CWinApp* pParent);
MyEchoSocket();
virtual ~MyEchoSocket();
private:
CWinApp* m_pParent;
};
#endif // !defined(AFX_MYECHOSOCKET_H__166D4120_2F94_4231_AE60_7C719E3EC05C__INCLUDED_)
// EchoServer.h
//
#if !defined(AFX_ECHOSERVER_H__7AA7D190_8407_49A5_A315_FB3E228E6F80__INCLUDED_)
#define AFX_ECHOSERVER_H__7AA7D190_8407_49A5_A315_FB3E228E6F80__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h" // main symbols
#include "MyEchoSocket.h"
class CEchoServerApp : public CWinApp
{
public:
void JobOnReceive();
void JobOnClose();
void JobOnAccept();
CEchoServerApp();
int m_port;
CString m_recieveddata;
CString m_status;
virtual BOOL InitInstance();
virtual int ExitInstance( );
//declare the Message-Loop ========================================
DECLARE_MESSAGE_MAP()
private:
MyEchoSocket m_sListener;
MyEchoSocket m_sConnected;
};
#endif // !defined(AFX_ECHOSERVER_H__7AA7D190_8407_49A5_A315_FB3E228E6F80__INCLUDED_)
// MyEchoSocket.cpp
//
#include "stdafx.h"
#include "EchoServer.h"
#include "MyEchoSocket.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
MyEchoSocket::MyEchoSocket()
{}
MyEchoSocket::~MyEchoSocket()
{}
void MyEchoSocket::OnAccept(int nErrorCode)
{
_cprintf_s("==> OnAccept ++++++++++++++\n");
if(nErrorCode==0)
{
reinterpret_cast<CEchoServerApp*>(m_pParent)->JobOnAccept();
}
CAsyncSocket::OnAccept(nErrorCode);
}
void MyEchoSocket::OnClose(int nErrorCode)
{
_cprintf_s("==> OnClose ++++++++++++++\n");
if(nErrorCode==0)
{
reinterpret_cast<CEchoServerApp*>(m_pParent)->JobOnClose();
}
CAsyncSocket::OnClose(nErrorCode);
}
void MyEchoSocket::OnConnect(int nErrorCode)
{
_cprintf_s("==> OnConnect ++++++++++++++\n");
CAsyncSocket::OnConnect(nErrorCode);
}
void MyEchoSocket::OnOutOfBandData(int nErrorCode)
{
CAsyncSocket::OnOutOfBandData(nErrorCode);
}
void MyEchoSocket::OnReceive(int nErrorCode)
{
_cprintf_s("==> OnReceive ++++++++++++++\n");
if(nErrorCode==0)
{
reinterpret_cast<CEchoServerApp*>(m_pParent)->JobOnReceive();
}
CAsyncSocket::OnReceive(nErrorCode);
}
void MyEchoSocket::OnSend(int nErrorCode)
{
_cprintf_s("==> OnSend ++++++++++++++\n");
CAsyncSocket::OnSend(nErrorCode);
}
BOOL MyEchoSocket::Create(UINT nSocketPort, int nSocketType, long lEvent, LPCTSTR lpszSocketAddress)
{
return CAsyncSocket::Create(nSocketPort, nSocketType, lEvent, lpszSocketAddress);
}
void MyEchoSocket::SetParentApp(CWinApp *pParent)
{
m_pParent=pParent;
}
// EchoServer.cpp
//
#include "stdafx.h"
#include "EchoServer.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//default Message-Loop of CWinApp =====================================
BEGIN_MESSAGE_MAP(CEchoServerApp, CWinApp)
END_MESSAGE_MAP()
CEchoServerApp::CEchoServerApp()
{}
CEchoServerApp theApp;
BOOL CEchoServerApp::InitInstance()
{
//I allocate a Console for CWinApp-Output =========================
BOOL R = AllocConsole();
if (!R)
{
AfxMessageBox("No Console");
return FALSE;
}
_cprintf_s("InitInstance()\n");
//prevent CWinApp from stopping without CWnd ======================
AfxOleSetUserCtrl(FALSE);
//initialize Windows Socket =======================================
if(AfxSocketInit()==FALSE)
{
_cprintf_s("Sockets Could Not Be Initialized");
return FALSE;
}
m_sListener.SetParentApp(this);
m_sConnected.SetParentApp(this);
m_port=12345;
// m_port=0; //Listen on all Ports does not work!
//I start the Listener here ==========================================
m_sListener.Create(m_port);
if(m_sListener.Listen()==FALSE)
{
_cprintf_s("Unable to Listen on that port,please try another port");
m_sListener.Close();
return FALSE;
}
_cprintf_s("++>Server is listening...\n");
return TRUE; //to start CWinApp::Run() -the MFC Message Loop- ========
}
int CEchoServerApp::ExitInstance()
{
_cprintf_s("ExitInstance: press ENTER to close App...");
char cb[256];
size_t sRead;
errno_t err = _cgets_s(cb, 255, &sRead);
//Cleanup ============================================================
BOOL R = FreeConsole();
if (!R)
{
//error
return 1;
}
return 0;
}
void CEchoServerApp::JobOnAccept()
{
CString strIP;
UINT port;
if(m_sListener.Accept(m_sConnected))
{
m_sConnected.GetSockName(strIP,port);
m_status="Client Connected,IP :"+ strIP;
_cprintf_s("++>%s Port:%d\n", m_status, port);
}
else
{
_cprintf_s("Can not Accept Connection");
}
}
void CEchoServerApp::JobOnClose()
{
_cprintf_s("++>post WM_QUIT\n");
AfxPostQuitMessage(0); //send WM_QUIT Message
}
void CEchoServerApp::JobOnReceive()
{
char pBuf[1024];
CString strData;
int iLen;
iLen=m_sConnected.Receive(pBuf,1023);
if(iLen==SOCKET_ERROR)
{
_cprintf_s("Could not Recieve");
}
else
{
pBuf[iLen]=NULL;
strData=pBuf;
m_recieveddata.Insert(m_recieveddata.GetLength(),strData); //store in class
_cprintf_s("++>%s\n", strData);
m_sConnected.Send(pBuf,iLen); //echo
//m_sConnected.ShutDown(0);
}
}
First of all:
YES its possible to use CAsyncSocket with full features without a CWin Window.
NO its no common Console App.
And it works fine :-)
You need a CWorker Class derived from CWinApp, because CWinApp:CWinThread has the MFC-Message-Loop Run().
class CWorkerApp :public CWinApp;
Second you need your CAsync Class derived from CAsyncSocket, to override the virtual Callbacks.
class CAsync :public CAsyncSocket;
Third you must tell CWinApp tu run without a CWin-Dialog, because default it stops, if it has no Window.
AfxOleSetUserCtrl(FALSE);
Keep in mind, you have no UI to that App. You just see it under Processes in Task-Manager and you can Kill it only that way.
But the good message, you can allocate a Console Window to put your DEBUG output there.
The rest I found in MSDN dokumentation, Sample EchoServer, and "of course" in Internet :))
I post the full source afterwards. They consist of
MyEchoSocket.h
EchoServer.h
MyEchoSocket.cpp
EchoServer.cpp
// MyEchoSocket.h : header file
//
#if !defined(AFX_MYECHOSOCKET_H__166D4120_2F94_4231_AE60_7C719E3EC05C__INCLUDED_)
#define AFX_MYECHOSOCKET_H__166D4120_2F94_4231_AE60_7C719E3EC05C__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class MyEchoSocket : public CAsyncSocket
{
public:
//my Overwrites of the Callbacks of the Socket-Events, I hook on by Create
virtual void OnReceive(int nErrorCode); //FD_READ
virtual void OnSend(int nErrorCode); //FD_WRITE
virtual void OnOutOfBandData(int nErrorCode); //FD_OOB
virtual void OnAccept(int nErrorCode); //FD_ACCEPT
virtual void OnConnect(int nErrorCode); //FD_CONNECT
virtual void OnClose(int nErrorCode); //FD_CLOSE
BOOL Create(
UINT nSocketPort = 0,
int nSocketType = SOCK_STREAM,
long lEvent = FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE,
LPCTSTR lpszSocketAddress = NULL
);
void SetParentApp(CWinApp* pParent);
MyEchoSocket();
virtual ~MyEchoSocket();
private:
CWinApp* m_pParent;
};
#endif // !defined(AFX_MYECHOSOCKET_H__166D4120_2F94_4231_AE60_7C719E3EC05C__INCLUDED_)
// EchoServer.h
//
#if !defined(AFX_ECHOSERVER_H__7AA7D190_8407_49A5_A315_FB3E228E6F80__INCLUDED_)
#define AFX_ECHOSERVER_H__7AA7D190_8407_49A5_A315_FB3E228E6F80__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h" // main symbols
#include "MyEchoSocket.h"
class CEchoServerApp : public CWinApp
{
public:
void JobOnReceive();
void JobOnClose();
void JobOnAccept();
CEchoServerApp();
int m_port;
CString m_recieveddata;
CString m_status;
virtual BOOL InitInstance();
virtual int ExitInstance( );
//declare the Message-Loop ========================================
DECLARE_MESSAGE_MAP()
private:
MyEchoSocket m_sListener;
MyEchoSocket m_sConnected;
};
#endif // !defined(AFX_ECHOSERVER_H__7AA7D190_8407_49A5_A315_FB3E228E6F80__INCLUDED_)
// MyEchoSocket.cpp
//
#include "stdafx.h"
#include "EchoServer.h"
#include "MyEchoSocket.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
MyEchoSocket::MyEchoSocket()
{}
MyEchoSocket::~MyEchoSocket()
{}
void MyEchoSocket::OnAccept(int nErrorCode)
{
_cprintf_s("==> OnAccept ++++++++++++++\n");
if(nErrorCode==0)
{
reinterpret_cast<CEchoServerApp*>(m_pParent)->JobOnAccept();
}
CAsyncSocket::OnAccept(nErrorCode);
}
void MyEchoSocket::OnClose(int nErrorCode)
{
_cprintf_s("==> OnClose ++++++++++++++\n");
if(nErrorCode==0)
{
reinterpret_cast<CEchoServerApp*>(m_pParent)->JobOnClose();
}
CAsyncSocket::OnClose(nErrorCode);
}
void MyEchoSocket::OnConnect(int nErrorCode)
{
_cprintf_s("==> OnConnect ++++++++++++++\n");
CAsyncSocket::OnConnect(nErrorCode);
}
void MyEchoSocket::OnOutOfBandData(int nErrorCode)
{
CAsyncSocket::OnOutOfBandData(nErrorCode);
}
void MyEchoSocket::OnReceive(int nErrorCode)
{
_cprintf_s("==> OnReceive ++++++++++++++\n");
if(nErrorCode==0)
{
reinterpret_cast<CEchoServerApp*>(m_pParent)->JobOnReceive();
}
CAsyncSocket::OnReceive(nErrorCode);
}
void MyEchoSocket::OnSend(int nErrorCode)
{
_cprintf_s("==> OnSend ++++++++++++++\n");
CAsyncSocket::OnSend(nErrorCode);
}
BOOL MyEchoSocket::Create(UINT nSocketPort, int nSocketType, long lEvent, LPCTSTR lpszSocketAddress)
{
return CAsyncSocket::Create(nSocketPort, nSocketType, lEvent, lpszSocketAddress);
}
void MyEchoSocket::SetParentApp(CWinApp *pParent)
{
m_pParent=pParent;
}
// EchoServer.cpp
//
#include "stdafx.h"
#include "EchoServer.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//default Message-Loop of CWinApp =====================================
BEGIN_MESSAGE_MAP(CEchoServerApp, CWinApp)
END_MESSAGE_MAP()
CEchoServerApp::CEchoServerApp()
{}
CEchoServerApp theApp;
BOOL CEchoServerApp::InitInstance()
{
//I allocate a Console for CWinApp-Output =========================
BOOL R = AllocConsole();
if (!R)
{
AfxMessageBox("No Console");
return FALSE;
}
_cprintf_s("InitInstance()\n");
//prevent CWinApp from stopping without CWnd ======================
AfxOleSetUserCtrl(FALSE);
//initialize Windows Socket =======================================
if(AfxSocketInit()==FALSE)
{
_cprintf_s("Sockets Could Not Be Initialized");
return FALSE;
}
m_sListener.SetParentApp(this);
m_sConnected.SetParentApp(this);
m_port=12345;
// m_port=0; //Listen on all Ports does not work!
//I start the Listener here ==========================================
m_sListener.Create(m_port);
if(m_sListener.Listen()==FALSE)
{
_cprintf_s("Unable to Listen on that port,please try another port");
m_sListener.Close();
return FALSE;
}
_cprintf_s("++>Server is listening...\n");
return TRUE; //to start CWinApp::Run() -the MFC Message Loop- ========
}
int CEchoServerApp::ExitInstance()
{
_cprintf_s("ExitInstance: press ENTER to close App...");
char cb[256];
size_t sRead;
errno_t err = _cgets_s(cb, 255, &sRead);
//Cleanup ============================================================
BOOL R = FreeConsole();
if (!R)
{
//error
return 1;
}
return 0;
}
void CEchoServerApp::JobOnAccept()
{
CString strIP;
UINT port;
if(m_sListener.Accept(m_sConnected))
{
m_sConnected.GetSockName(strIP,port);
m_status="Client Connected,IP :"+ strIP;
_cprintf_s("++>%s Port:%d\n", m_status, port);
}
else
{
_cprintf_s("Can not Accept Connection");
}
}
void CEchoServerApp::JobOnClose()
{
_cprintf_s("++>post WM_QUIT\n");
AfxPostQuitMessage(0); //send WM_QUIT Message
}
void CEchoServerApp::JobOnReceive()
{
char pBuf[1024];
CString strData;
int iLen;
iLen=m_sConnected.Receive(pBuf,1023);
if(iLen==SOCKET_ERROR)
{
_cprintf_s("Could not Recieve");
}
else
{
pBuf[iLen]=NULL;
strData=pBuf;
m_recieveddata.Insert(m_recieveddata.GetLength(),strData); //store in class
_cprintf_s("++>%s\n", strData);
m_sConnected.Send(pBuf,iLen); //echo
//m_sConnected.ShutDown(0);
}
}