// SpeedTestDlg.cpp : implementation file
//
#include "stdafx.h"
#include "SpeedTest.h"
#include "SpeedTestDlg.h"
#include <SockUtil.h>
#include <atlbase.h>
#include "..\..\Svr\HostDnsSvs.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSpeedTestDlg dialog
CSpeedTestDlg::CSpeedTestDlg(CWnd* pParent /*=NULL*/)
: CDialog(CSpeedTestDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CSpeedTestDlg)
m_strClients = _T("");
m_strHost = _T("");
m_nPort = 1739;
m_dwTime = 0;
m_nBytes = 0;
m_nNagleTime = 0;
m_bNagle = FALSE;
m_nRepeat = 100;
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CSpeedTestDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CSpeedTestDlg)
DDX_Text(pDX, IDC_HOST_EDIT, m_strHost);
DDX_Text(pDX, IDC_PORT_EDIT, m_nPort);
DDX_Text(pDX, IDC_TIMECOST_EDIT, m_dwTime);
DDX_Text(pDX, IDC_BYTES_EDIT, m_nBytes);
DDX_Text(pDX, IDC_NAGLETIME_EDIT, m_nNagleTime);
DDX_Check(pDX, IDC_NAGLE_CHECK, m_bNagle);
DDX_Text(pDX, IDC_REPEAT_EDIT, m_nRepeat);
DDV_MinMaxUInt(pDX, m_nRepeat, 1, 8000);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CSpeedTestDlg, CDialog)
//{{AFX_MSG_MAP(CSpeedTestDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_CONNECT_BUTTON, OnConnectButton)
ON_BN_CLICKED(IDC_DISCONNECT_BUTTON, OnDisconnectButton)
ON_BN_CLICKED(IDC_ASYN_NAGLE_BUTTON, OnAsynNagleButton)
ON_BN_CLICKED(IDC_ASYN_BATCH_BUTTON, OnAsynBatchButton)
ON_BN_CLICKED(IDC_SYN_ONE_BUTTON, OnSynOneButton)
ON_WM_DESTROY()
ON_BN_CLICKED(IDC_NAGLE_CHECK, OnNagleCheck)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSpeedTestDlg message handlers
BOOL CSpeedTestDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
void CSpeedTestDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CSpeedTestDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CSpeedTestDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
bool CSpeedTestDlg::Run()
{
DWORD dwBytes=0;
//make sure if any data is available
if(!IOCtl(FIONREAD, dwBytes)||dwBytes<sizeof(CStreamHeader))
return false;
BYTE *pBuffer=new BYTE[dwBytes];
m_nBytes +=RecvBigChunk(pBuffer, dwBytes);
m_dwTime=::GetTickCount()-m_dwStart;
UpdateData(FALSE);
//you could decode the binary data here
//the binary data contains various infos such as method ids, returned data, or error codes if available here
delete []pBuffer;
//Peek if any data is available
dwBytes=0;
IOCtl(FIONREAD, dwBytes);
if(dwBytes && dwBytes >= sizeof(CStreamHeader))
{
while(!::PostMessage(CAsySocketClient::GetWnd(), WM_SOCKET_CLIENT_NOTIFY, m_hSocket, FD_READ))
{
::Sleep(1);
}
}
return true;
}
void CSpeedTestDlg::OnConnectButton()
{
UpdateData(TRUE);
//set application instance
SetInstance(AfxGetApp()->m_hInstance);
//create a local socket
CAsySocket::Create(0);
//connect the local socket to a server (m_strHost) listening socket (m_nPort) asynchronously
//connection time out is 30 seconds by default.
//If you don't like this default, call the function CAsySocketClient::SetConnectTimeout
Connect(m_strHost, m_nPort);
}
void CSpeedTestDlg::OnClose(WPARAM hSocket, LPARAM lError)
{
GetDlgItem(IDC_ASYN_NAGLE_BUTTON)->EnableWindow(FALSE);
GetDlgItem(IDC_ASYN_BATCH_BUTTON)->EnableWindow(FALSE);
GetDlgItem(IDC_SYN_ONE_BUTTON)->EnableWindow(FALSE);
m_bNagle=FALSE;
UpdateData(FALSE);
CAsySocketClient::OnClose(hSocket, lError);
}
void CSpeedTestDlg::OnConnect(WPARAM hSocket, LPARAM lError)
{
if(lError==S_OK)
{
DWORD dwOldEvents=m_lEvent;
GetDlgItem(IDC_ASYN_NAGLE_BUTTON)->EnableWindow(TRUE);
GetDlgItem(IDC_ASYN_BATCH_BUTTON)->EnableWindow(TRUE);
GetDlgItem(IDC_SYN_ONE_BUTTON)->EnableWindow(TRUE);
CStreamHeader StreamHeader;
CPacking Packing;
StreamHeader.m_nValue=HOST_DNS_SVS_SOCKET; //HostDNS class ID
//switch to blocking mode, and make logical in coding simpler
AsyncSelect(0);
//Remember that the SocketPro server can provide multiple svervices
//Tells the SocketPro server to switch to HostDNS service only
SendBigChunk(&StreamHeader, sizeof(StreamHeader));
//Get the returned result
RecvBigChunk(&StreamHeader, sizeof(StreamHeader));
if(StreamHeader.m_nValue!=S_OK)
{
MessageBox("No requried class recognized!");
}
//switch back to non-blocking mode, and don't need the event FD_CONNECT any more
AsyncSelect(dwOldEvents &~(FD_CONNECT));
m_bNagle=TRUE;
UpdateData(FALSE);
}
else
{
CString strErrMsg;
strErrMsg.Format("Error happens in connecting to a host, and error code =%d\n", lError);
MessageBox(strErrMsg);
}
}
void CSpeedTestDlg::OnDisconnectButton()
{
GetDlgItem(IDC_ASYN_NAGLE_BUTTON)->EnableWindow(FALSE);
GetDlgItem(IDC_ASYN_BATCH_BUTTON)->EnableWindow(FALSE);
GetDlgItem(IDC_SYN_ONE_BUTTON)->EnableWindow(FALSE);
//gracefully shut down socket
ShutDown();
// Close();
m_bNagle=FALSE;
UpdateData(FALSE);
}
void CSpeedTestDlg::OnAsynNagleButton()
{
UpdateData(TRUE);
m_dwStart=::GetTickCount();
unsigned long nIndex=0;
m_nBytes=0;
CStreamHeader StreamHeader;
StreamHeader.m_nLen=0;
StreamHeader.m_nValue=HOST_DNS_SVS_METHOD_ID_GET_CLIENTS;
//Coalescing happens automatically through Nagle algorithm
//Multiple StreamHeaders are sent to a SocketPro server using one big stream.
//You can watch the sizes of big streams at the server side.
//This will reduce data round-trips for efficient use of network.
for(nIndex=0; nIndex<m_nRepeat; nIndex++)
{
//Nagle algorithm may cost a little time, which depends on your machine
SendBigChunk(&StreamHeader, sizeof(StreamHeader));
}
m_nNagleTime=::GetTickCount()-m_dwStart;
UpdateData(FALSE);
}
void CSpeedTestDlg::OnAsynBatchButton()
{
UpdateData(TRUE);
m_dwStart=::GetTickCount();
m_nBytes=0;
unsigned long nIndex=0;
CStreamHeader *pStreamHeader=new CStreamHeader [m_nRepeat];
for(nIndex=0; nIndex<m_nRepeat; nIndex++)
{
pStreamHeader[nIndex].m_nLen=0;
pStreamHeader[nIndex].m_nValue=HOST_DNS_SVS_METHOD_ID_GET_CLIENTS;
}
//Coalescing by our code instead of Nagle algorithm
//Multiple StreamHeaders are sent to a SocketPro server using one big stream.
//You can watch the sizes of big streams at the server side.
//This will reduce data round-trips for efficient use of network.
SendBigChunk(pStreamHeader, m_nRepeat*sizeof(CStreamHeader));
delete []pStreamHeader;
m_nNagleTime=::GetTickCount()-m_dwStart;
UpdateData(FALSE);
}
void CSpeedTestDlg::OnSynOneButton()
{
char *strBuffer;
unsigned long nIndex;
CStreamHeader StreamHeader;
//remember the old events
DWORD dwOldEvents=m_lEvent;
UpdateData(TRUE);
m_nBytes=0;
//switch to blocking mode
AsyncSelect(0);
m_dwStart=::GetTickCount();
for(nIndex=0; nIndex<m_nRepeat; nIndex++)
{
StreamHeader.m_nLen=0;
StreamHeader.m_nValue=HOST_DNS_SVS_METHOD_ID_GET_CLIENTS;
SendBigChunk(&StreamHeader, sizeof(StreamHeader));
//Get the returned stream header
m_nBytes += RecvBigChunk(&StreamHeader, sizeof(StreamHeader));
strBuffer = new char [StreamHeader.m_nLen];
//Retrieve the binary data
m_nBytes += RecvBigChunk(strBuffer, StreamHeader.m_nLen);
delete []strBuffer;
}
m_dwTime=::GetTickCount()-m_dwStart;
UpdateData(FALSE);
//switch back to non-blocking mode
AsyncSelect(dwOldEvents);
}
void CSpeedTestDlg::OnDestroy()
{
if(IsOpen())
{
OnDisconnectButton();
}
CDialog::OnDestroy();
}
void CSpeedTestDlg::OnNagleCheck()
{
UpdateData(TRUE);
m_dwStart=::GetTickCount();
if(IsOpen())
{
CStreamHeader StreamHeader;
//Client side
/* if(m_bNagle)
{
BOOL bNoDelay=(!m_bNagle);
SetSockOpt(TCP_NODELAY, &bNoDelay, sizeof(bNoDelay), IPPROTO_TCP);
}
else
{
BOOL bNoDelay=(!m_bNagle);
SetSockOpt(TCP_NODELAY, &bNoDelay, sizeof(bNoDelay), IPPROTO_TCP);
}*/
//Server side
if(m_bNagle)
StreamHeader.m_nValue=ENABLE_NAGLE; //enable
else
StreamHeader.m_nValue=DISABLE_NAGLE; //disable
SendBigChunk(&StreamHeader, sizeof(StreamHeader));
}
}