??xml version="1.0" encoding="utf-8" standalone="yes"?>
在stdafx.h
中加入:
#undef WINVER
#define WINVER 0x0500
*************************************************************
#ifndef SM_CMONITORS
typedef HANDLE HMONITOR;
#endif
#ifndef DISPLAY_DEVICE_PRIMARY_DEVICE
typedef struct _DISPLAY_DEVICE {
DWORD cb;
TCHAR DeviceName[32];
TCHAR DeviceString[128];
DWORD StateFlags;
} DISPLAY_DEVICE, *PDISPLAY_DEVICE, *LPDISPLAY_DEVICE;
#define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001
#define DISPLAY_DEVICE_MULTI_DRIVER 0x00000002
#define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004
#define DISPLAY_DEVICE_VGA 0x00000010
#endif
typedef BOOL (WINAPI* pEnumDisplayDevices)(PVOID,DWORD,PVOID,DWORD);
typedef BOOL (WINAPI* pEnumDisplaySettings)(PVOID,DWORD,PVOID);
pEnumDisplayDevices pStartEnumDisplayDevices;
pEnumDisplaySettings pStartEnumDisplaySettings;
*********************************************************************
int iCount;
pStartEnumDisplayDevices = (pEnumDisplayDevices)GetProcAddress(LoadLibrary("USER32"), "EnumDisplayDevicesA");
pStartEnumDisplaySettings = (pEnumDisplaySettings)GetProcAddress(LoadLibrary("USER32"), "EnumDisplaySettingsA");
if (pStartEnumDisplayDevices && pStartEnumDisplaySettings)
{
DISPLAY_DEVICE dd;
DEVMODE dv;
ZeroMemory(&dv, sizeof(dv));
ZeroMemory(&dd, sizeof(dd));
dv.dmSize = sizeof(dv);
dd.cb = sizeof(dd);
for (iCount=0; (*pStartEnumDisplayDevices)(NULL, iCount, &dd, 0); iCount++)
{
(*pStartEnumDisplaySettings)(dd.DeviceName,ENUM_CURRENT_SETTINGS,&dv);
if((dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)
&&(dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE))
{
CString strDispName,strScreen,strColor,strFreq;
strDispName.Format(_T("Device Name: %s "),dd.DeviceString);
SetDlgItemText(IDC_STATIC_DISP_NAME,strDispName);
strScreen.Format(_T("%d×%d "),dv.dmPelsWidth,dv.dmPelsHeight);
SetDlgItemText(IDC_STATIC_FREQ,strScreen);
strColor.Format(_T("%d Bit"),dv.dmBitsPerPel);
SetDlgItemText(IDC_STATIC_COLOR,strColor);
strFreq.Format(_T("%d Hz"),dv.dmDisplayFrequency);
SetDlgItemText(IDC_STATIC_REFRESH_FREQ,strFreq);
}
}
}
]]>
跟踪E序?/span> _heap_alloc_dbg
void * __cdecl _heap_alloc_dbg(
size_t nSize,
int nBlockUse,
const char * szFileName,
int nLine
)
{
long lRequest;
size_t blockSize;
int fIgnore = FALSE;
_CrtMemBlockHeader * pHead;
/* verify heap before allocation */
if (_crtDbgFlag & _CRTDBG_CHECK_ALWAYS_DF)
_ASSERTE(_CrtCheckMemory());
lRequest = _lRequestCurr;
/* break into debugger at specific memory allocation */
if (lRequest == _crtBreakAlloc)
_CrtDbgBreak();
// here is the place were the app stops
// ... function continuous
_crtBreakAlloc
?/span>
-1
?/span>
lRequest
?/span>
long
型,?/span>
new
一ơ,
_lRequestCurr
每调用一?/span>
new
Q自动加
1
Q当
2147483647
再加
1
变成
-2147483648
Q一直篏加到
-1
Q然后调?/span>
_CrtDbgBreak()
Q出错。看似是q个原因Qؓ了进一步确认,~写试E序
class AA
{
char aa1[10];
char aa2[12];
};
int main(int argc, char* argv[])
{
AA *pp;
while(1)
{
pp=new AA;
delete pp;
}
}
几个时后复C此现象?/span>
|上查找0X10212AD0 有如下线索:
http://www.experts-exchange.com/Programming/Programming_Languages/MFC/Q_21088390.html
.opt | 工程关于开发环境的参数文g。如工具条位|等信息Q?/td> |
.aps | (AppStudio File),资源辅助文g,二进制格?一般不用去他. |
.clw | ClassWizard信息文g,实际上是INI文g的格?有兴可以研I一?有时候ClassWizard出问?手工修改CLW文g可以解决.如果此文件不存在的话,每次用ClassWizard的时候绘提示你是否重? |
.dsp | (DeveloperStudio Project):目文g,文本格式,不过不熟悉的话不要手工修?DSW(DeveloperStudio Workspace)是工作区文g,其他特点和DSP差不? |
.plg | 是编译信息文?~译时的error和warning信息文gQ实际上是一个html文gQ?一般用处不?在Tools->Options里面有个选项可以控制q个文g的生? |
.hpj | (Help Project)是生成帮助文件的工程,用microsfot Help Compiler可以处理. |
.mdp | (Microsoft DevStudio Project)是旧版本的项目文?如果要打开此文件的?会提CZ是否转换成新的DSP格式. |
.bsc | 是用于浏览项目信息的,如果用Source Brower的话必Lq个文g.如果不用q个功能的话,可以在Project Options里面LGenerate Browse Info File,可以加快~译速度. |
.map | 是执行文件的映像信息U录文g,除非对系l底层非常熟?q个文g一般用不着. |
.pch | (Pre-Compiled File)是预~译文g,可以加快~译速度,但是文g非常? |
.pdb | (Program Database)记录了程序有关的一些数据和调试信息,在调试的时候可能有? |
.exp | 只有在编译DLL的时候才会生?记录了DLL文g中的一些信?一般也没什么用. |
.ncb | 无编译浏览文?no compile browser)。当自动完成功能出问题时可以删除此文件。build后会自动生成?/td> |
ZIP Multicast的传输和实现
前面讨论的开发网l通信的经典入门采用的是WSAAsyncSelect的异步I/O模型Q本文将讨论WSAEventSelect异步I/O模型?
WSAEventSelect模型有点cMWSAAsyncSelect模型Q不同的是他不是用消息映的方式来响应网l事Ӟ而是用等待多重事件的方式来响应网l事件。下面是用WSAEventSelect模型和多U程机制做的一个简单的服务器程序的.cpp?h文gQ应用程序基于MFC的标准对话框。实现接受多个客L的连接请求,q记录下所有客L的相关信息,昄在列表框中?/p>
// serverDlg.cpp : implementation file
//
#include "stdafx.h"
#include "server.h"
#include "serverDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
SOCKET Accept; file://?/font>于新的一个连接通信的套接字
WSAEVENT NewEvent; file://?/font>应于新的套接字的C?br />SOCKET Socket[WSA_MAXIMUM_WAIT_EVENTS]; file://?/font>放所有生成的套接?br />WSAEVENT Event[WSA_MAXIMUM_WAIT_EVENTS]; file://?/font>放所有生成的事g对象
int EventTotal; file://?/font>建的事gL
int Index; file://{?/font>待多重事件函数的q回?br />WSANETWORKEVENTS NetworkEvents; file://?/font>于接收套接字上发生的|络事gcd以及可能出现的错
误代?/p>
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
file://{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
file://}}AFX_DATA
// ClassWizard generated virtual function overrides
file://{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
file://}}AFX_VIRTUAL
// Implementation
protected:
file://{{AFX_MSG(CAboutDlg)
file://}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
file://{{AFX_DATA_INIT(CAboutDlg)
file://}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
file://{{AFX_DATA_MAP(CAboutDlg)
file://}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
file://{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
file://}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CServerDlg dialog
CServerDlg::CServerDlg(CWnd* pParent /*=NULL*/)
: CDialog(CServerDlg::IDD, pParent)
{
file://{{AFX_DATA_INIT(CServerDlg)
// NOTE: the ClassWizard will add member initialization here
file://}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_Connectnum = 0;
m_NetworkID = 0;
EventTotal = 0;
for(int i = 0; i < MAX_CLIENT_NUM; i++)
{
ZeroMemory(&m_ClientInfo[i], sizeof(client_info));
}
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CServerDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
file://{{AFX_DATA_MAP(CServerDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
file://}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CServerDlg, CDialog)
file://{{AFX_MSG_MAP(CServerDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_TIMER()
file://}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CServerDlg message handlers
BOOL CServerDlg::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
WSADATA wsaData;
int ret;
ret = WSAStartup(MAKEWORD(2,2), &wsaData);
if(ret != 0)
{
MessageBox("初始化套接字p|!");
return FALSE;
}
file://?/font>Z个套接字
m_ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(m_ListenSocket == INVALID_SOCKET)
{
MessageBox("创徏套接字失?");
closesocket(m_ListenSocket);
WSACleanup();
return FALSE;
}
file://l?/font>定到指定的端口上
sockaddr_in localaddr;
localaddr.sin_family = AF_INET;
localaddr.sin_port = htons(1688);
localaddr.sin_addr.s_addr = 0;
if(bind(m_ListenSocket, (const struct sockaddr*)&localaddr, sizeof(sockaddr))
== SOCKET_ERROR)
{
MessageBox("l定地址p|!");
closesocket(m_ListenSocket);
WSACleanup();
return FALSE;
}
NewEvent = WSACreateEvent(); file://?/font>Z个新的事件对?/p>
file://?/font>创徏的事件对象与前面创徏的套接字兌在一?q注册网l事件类?br /> if(WSAEventSelect(m_ListenSocket, NewEvent, FD_ACCEPT | FD_CLOSE) == SOCKET_ERROR)
{
MessageBox("注册|络事gp|!");
closesocket(m_ListenSocket);
WSACleanup();
return FALSE;
}
file://?/font>创徏的套接字处于监听状?br /> listen(m_ListenSocket, 5);
Event[EventTotal] = NewEvent;
Socket[EventTotal] = m_ListenSocket;
EventTotal++;
file://?/font>|List控g的图象列?br /> HICON hIcon;
m_imagelist.Create(16, 16, 0, 4, 4); // 32, 32 for large icons
hIcon = AfxGetApp()->LoadIcon(IDI_CLIENT_INFO);
m_imagelist.SetBkColor (RGB(248,232,224));
m_imagelist.Add(hIcon);
pList = (CListCtrl*)GetDlgItem(IDC_CLIENT_INFO);
pList->SetImageList(&m_imagelist, LVSIL_SMALL);
pList->SetBkColor(RGB(248,232,224));
pList->SetTextBkColor(RGB(248,232,224));
pList->InsertColumn(0," 客户?,LVCFMT_CENTER,90, 0);
pList->InsertColumn(1,"|络ID",LVCFMT_CENTER,50,1);
pList->InsertColumn(2,"IP地址",LVCFMT_CENTER,100,2);
pList->InsertColumn (3,"d旉",LVCFMT_CENTER,120,3);
pList->InsertColumn (4,"在线旉",LVCFMT_CENTER,100,4);
SetTimer(1, 1000, NULL);
file://?/font>动核心处理线E?br /> AfxBeginThread(KernelWorkThread,this,THREAD_PRIORITY_NORMAL);
return TRUE; // return TRUE unless you set the focus to a control
}
void CServerDlg::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 CServerDlg::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 CServerDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
file://?/font>
心处理线E? 响应q处理各U网l事?br />UINT KernelWorkThread(LPVOID pParam)
{
int len = sizeof(sockaddr);
CServerDlg* dlg;
dlg = (CServerDlg*)pParam;
while(1)
{
Index = WSAWaitForMultipleEvents(EventTotal, Event, FALSE, WSA_INFINITE, FALSE);
WSAEnumNetworkEvents(Socket[Index - WSA_WAIT_EVENT_0],
Event[Index - WSA_WAIT_EVENT_0],
&NetworkEvents);
if(NetworkEvents.lNetworkEvents & FD_ACCEPT)
file://q?/font>接事?br /> {
if(NetworkEvents.iErrorCode[FD_ACCEPT_BIT] != 0)
{
dlg->MessageBox("接受q接事gp|!");
break;
}
Accept = accept(Socket[Index - WSA_WAIT_EVENT_0],
(struct sockaddr*)&(dlg->clientaddr), &len);
if(Accept == INVALID_SOCKET)
{
dlg->MessageBox("接受q接p|!");
break;
}
if(EventTotal > WSA_MAXIMUM_WAIT_EVENTS)
{
dlg->MessageBox("q接个数溢出,拒绝接受!");
break;
}
NewEvent = WSACreateEvent();
if(WSAEventSelect(Accept, NewEvent, FD_READ | FD_WRITE | FD_CLOSE)
== SOCKET_ERROR)
{
dlg->MessageBox("注册|络事gp|!");
closesocket(Accept);
break;
}
Event[EventTotal] = NewEvent;
Socket[EventTotal] = Accept;
EventTotal ++;
}
if(NetworkEvents.lNetworkEvents & FD_READ)
file://?/font>取数据事?br /> {
if(NetworkEvents.iErrorCode[FD_READ_BIT] != 0)
{
dlg->MessageBox("M件失?");
break;
}
if(dlg->OnReceive(Socket[Index - WSA_WAIT_EVENT_0]) == FALSE)
{
dlg->MessageBox("d数据p|!");
break;
}
}
if(NetworkEvents.lNetworkEvents & FD_CLOSE)
file://?/font>闭套接字事g
{
if(NetworkEvents.iErrorCode[FD_CLOSE_BIT] != 0)
{
dlg->MessageBox("关闭事gp|!");
break;
}
if(dlg->OnClose(Socket[Index - WSA_WAIT_EVENT_0]) == FALSE)
{
dlg->MessageBox("关闭套接字失?");
break;
}
}
}
return 0;
}
BOOL CServerDlg::OnClose(SOCKET pSocket)
{
int i, exitnum;
for(i = 0; i < m_Connectnum; i++)
{
if(m_ClientInfo[i].Client_Socket == pSocket)
{
exitnum = i;
}
}
for(i = exitnum; i < m_Connectnum; i++)
{
memcpy(&m_ClientInfo[i], &m_ClientInfo[i+1], sizeof(client_info));
}
m_Connectnum --;
file://?/font>所有客L发送在U客户信息的报文
cmd_client_info ClientInfo;
ClientInfo.cmd_type = CMD_CLIENT_INFO;
ClientInfo.client_num = m_Connectnum;
for(i=0; i<=m_Connectnum; i++)
{
ClientInfo.Networks_ID[i] = m_ClientInfo[i].Network_ID;
strcpy(ClientInfo.users_name[i], m_ClientInfo[i].User_Name);
strcpy(ClientInfo.clients_ipaddr[i], inet_ntoa(m_ClientInfo[i].Client_Addr.sin_addr));
}
for(i=0; i<=m_Connectnum; i++)
{
send(m_ClientInfo[i].Client_Socket, (char*)&ClientInfo, sizeof(cmd_client_info), NULL);
}
closesocket(pSocket);
pList->DeleteItem(exitnum);
return TRUE;
}
BOOL CServerDlg::OnReceive(SOCKET pSocket)
{
static char rcvbuf[65535]; file://?/font>收缓冲区
int ret;
int offset=0;
find_type* pFindType;
int i = 0;
CTime m_current_time=CTime::GetCurrentTime ();
CString strTime = m_current_time.Format("%c");
CString networkid; file://?/font>表框的网lID?/p>
ret = recv(pSocket, rcvbuf, 65535, 0);
if(ret == OPERATION_ERROR)
return FALSE;
while(offset < ret)
{
pFindType = (find_type*)(rcvbuf+offset);
switch(pFindType->cmd_type)
{
case CMD_HELLO:
cmd_hello Hello;
memcpy(&Hello, rcvbuf+offset, sizeof(cmd_hello));
offset+=sizeof(cmd_hello);
cmd_hello_resp HelloResp;
m_NetworkID ++;
HelloResp.cmd_type = CMD_HELLO_RESP;
HelloResp.Network_ID = m_NetworkID;
strcpy(HelloResp.user_name, Hello.user_name);
memcpy((struct sockaddr*)&(m_ClientInfo[m_Connectnum].Client_Addr),
(const struct sockaddr*)&clientaddr, sizeof(sockaddr));
m_ClientInfo[m_Connectnum].Client_Socket = Accept;
strcpy(m_ClientInfo[m_Connectnum].User_Name, HelloResp.user_name);
m_ClientInfo[m_Connectnum].Network_ID = m_NetworkID;
m_ClientInfo[m_Connectnum].Login_Time = m_current_time;
send(pSocket, (char*)&HelloResp, sizeof(cmd_hello_resp), NULL);
file://?/font>d的客L发送回应报?br /> Sleep(200);
cmd_client_info ClientInfo;
ClientInfo.cmd_type = CMD_CLIENT_INFO;
ClientInfo.client_num = m_Connectnum +1;
for(i=0; i<=m_Connectnum; i++)
{
ClientInfo.Networks_ID[i] = m_ClientInfo[i].Network_ID;
strcpy(ClientInfo.users_name[i], m_ClientInfo[i].User_Name);
strcpy(ClientInfo.clients_ipaddr[i],
inet_ntoa(m_ClientInfo[i].Client_Addr.sin_addr));
}
file://?/font>所有在U客L发送在U客户信息报?br /> for(i=0; i<=m_Connectnum; i++)
{
send(m_ClientInfo[i].Client_Socket, (char*)&ClientInfo,
sizeof(cmd_client_info), NULL);
}
file://?/font>新客L信息列表
networkid.Format("%d", m_NetworkID);
LVITEM lvinsert;
lvinsert.mask=LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
lvinsert.iItem=m_Connectnum;
lvinsert.iSubItem=0;
lvinsert.cchTextMax=20;
lvinsert.pszText=HelloResp.user_name;
lvinsert.iImage = 0;
pList->InsertItem (&lvinsert);
pList->SetItemText (m_Connectnum,1,networkid);
pList->SetItemText(m_Connectnum,2,
inet_ntoa(m_ClientInfo[m_Connectnum].Client_Addr.sin_addr));
pList->SetItemText (m_Connectnum,3,strTime);
m_Connectnum ++;
break;
case CMD_ASK:
cmd_ask Ask;
cmd_ask_resp AskResp;
memcpy(&Ask,rcvbuf+offset,sizeof(cmd_ask));
offset+=sizeof(cmd_ask);
AskResp.cmd_type = CMD_ASK_RESP;
AskResp.Network_ID = Ask.Network_ID;
for(i=0; i<m_Connectnum; i++)
{
if(m_ClientInfo[i].Network_ID == Ask.Network_ID)
{
strcpy(AskResp.pData1,m_ClientInfo[i].User_Name);
strcat(AskResp.pData1, ":");
}
}
strcpy(AskResp.pData2, Ask.pData);
for(i=0; i<m_Connectnum; i++)
{
send(m_ClientInfo[i].Client_Socket, (char*)&AskResp, sizeof(AskResp), 0);
}
break;
case CMD_GOODBYE:
closesocket(pSocket);
break;
default:
break;
}
}
return TRUE;
}
BOOL CServerDlg::OnSend(SOCKET pSocket)
{
return TRUE;
}
void CServerDlg::OnOK()
{
closesocket(m_ListenSocket);
WSACleanup();
CDialog::OnOK();
}
void CServerDlg::OnTimer(UINT nIDEvent)
{
CTime m_current_time = CTime::GetCurrentTime();
CTimeSpan logintimes;
CString login_times;
CString networkid; file://?/font>表框的网lID?br />
for(int i=0; i<m_Connectnum; i++)
{
logintimes = m_current_time - m_ClientInfo[i].Login_Time;
login_times.Format("%d时%d?dU?, logintimes.GetHours(),
logintimes.GetMinutes(),
logintimes.GetSeconds());
pList->SetItemText (i,4,login_times);
}
CDialog::OnTimer(nIDEvent);
}
// serverDlg.h : header file
//
#if !defined(AFX_SERVERDLG_H__B0AA0367_C1F4_11D4_AB1C_0080C8D6FEA5__INCLUDED_)
#define AFX_SERVERDLG_H__B0AA0367_C1F4_11D4_AB1C_0080C8D6FEA5__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "global.h"
/////////////////////////////////////////////////////////////////////////////
// CServerDlg dialog
class CServerDlg : public CDialog
{
file://?/font>局函数
friend UINT KernelWorkThread(LPVOID pParam);
// Construction
public:
CListCtrl* pList; file://?/font>L在线信息列表框对?br /> CImageList m_imagelist;
SOCKET m_ListenSocket; file://?/font>于监听端口的套接?br /> client_info m_ClientInfo[MAX_CLIENT_NUM]; file://?/font>存在U客L信息的结构体数组
sockaddr_in clientaddr; file://?/font>存发赯接的客户端地址
int m_Connectnum; file://?/font>U客L个数
int m_NetworkID; file://q?/font>回给客户端的|络ID?/p>
BOOL OnSend(SOCKET pSocket); file://?/font>送数据网l事件的响应函数
BOOL OnReceive(SOCKET pSocket); file://?/font>收数据网l事件的响应函数
BOOL OnClose(SOCKET pSocket); file://?/font>闭套接字|络事g的响应函?/p>
CServerDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
file://{{AFX_DATA(CServerDlg)
enum { IDD = IDD_SERVER_DIALOG };
// NOTE: the ClassWizard will add data members here
file://}}AFX_DATA
// ClassWizard generated virtual function overrides
file://{{AFX_VIRTUAL(CServerDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
file://}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
file://{{AFX_MSG(CServerDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
virtual void OnOK();
afx_msg void OnTimer(UINT nIDEvent);
file://}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
1 什么是回调
软g模块之间L存在着一定的接口Q从调用方式上,可以把他们分Zc:同步调用、回调和异步调用。同步调用是一U阻塞式调用Q调用方要等待对Ҏ行完毕才q回Q它是一U单向调用;回调是一U双向调用模式,也就是说Q被调用方在接口被调用时也会调用Ҏ的接口;异步调用是一U类似消息或事g的机Ӟ不过它的调用方向刚好相反Q接口的服务在收到某U讯息或发生某种事gӞ会主动通知客户方(卌用客h的接口)。回调和异步调用的关p非常紧密,通常我们使用回调来实现异步消息的注册Q通过异步调用来实现消息的通知。同步调用是三者当中最单的Q而回调又常常是异步调用的基础Q因此,下面我们着重讨论回调机制在不同软g架构中的实现?
对于不同cd的语aQ如l构化语a和对象语aQ、^収ͼWin32、JDKQ或构架QCORBA、DCOM、WebServiceQ,客户和服务的交互除了同步方式以外Q都需要具备一定的异步通知机制Q让服务方(或接口提供方Q在某些情况下能够主动通知客户Q而回调是实现异步的一个最L途径?
对于一般的l构化语aQ可以通过回调函数来实现回调。回调函C是一个函数或q程Q不q它是一个由调用方自己实玎ͼ供被调用方用的Ҏ函数?
在面向对象的语言中,回调则是通过接口或抽象类来实现的Q我们把实现q种接口的类成ؓ回调c,回调cȝ对象成ؓ回调对象。对于象C++或Object Pascalq些兼容了过E特性的对象语言Q不仅提供了回调对象、回调方法等Ҏ,也能兼容q程语言的回调函数机制?
Windowsq_的消息机制也可以看作是回调的一U应用,我们通过pȝ提供的接口注册消息处理函敎ͼ卛_调函敎ͼQ从而实现接收、处理消息的目的。由于Windowsq_的API是用C语言来构建的Q我们可以认为它也是回调函数的一个特例?
对于分布式组件代理体pCORBAQ异步处理有多种方式Q如回调、事件服务、通知服务{。事件服务和通知服务是CORBA用来处理异步消息的标准服务,他们主要负责消息的处理、派发、维护等工作。对一些简单的异步处理q程Q我们可以通过回调机制来实现?
下面我们集中比较h代表性的语言QC、Object PascalQ和架构QCORBAQ来分析回调的实现方式、具体作用等?
2.1 函数指针
回调在C语言中是通过函数指针来实现的,通过回调函数的地址传给被调函数从而实现回调。因此,要实现回调,必须首先定义函数指针Q请看下面的例子Q?
|
可以看出Q函数的定义和函数指针的定义非常cM?
一般的化,Z化函数指针类型的变量定义Q提高程序的可读性,我们需要把函数指针cd自定义一下?
|
回调函数可以象普通函C栯E序调用Q但是只有它被当作参C递给被调函数时才能称作回调函数?
被调函数的例子:
|
如果赋了不同的值给该参敎ͼ那么调用者将调用不同地址的函数。赋值可以发生在q行Ӟq样使你能实现动态绑定?
2.2 参数传递规?/SPAN>
到目前ؓ止,我们只讨Z函数指针及回调而没有去注意ANSI C/C++的编译器规范。许多编译器有几U调用规范。如在Visual C++中,可以在函数类型前加_cdeclQ_stdcall或者_pascal来表C其调用规范Q默认ؓ_cdeclQ。C++ Builder也支持_fastcall调用规范。调用规范媄响编译器产生的给定函数名Q参C递的序Q从叛_左或从左到右Q,堆栈清理责QQ调用者或者被调用者)以及参数传递机Ӟ堆栈QCPU寄存器等Q?
调用规范看成是函数cd的一部分是很重要的;不能用不兼容的调用规范将地址赋值给函数指针。例如:
|
指针p和callee()的类型不兼容Q因为它们有不同的调用规范。因此不能将被调用者的地址赋值给指针pQ尽两者有相同的返回值和参数?
2.3 应用举例
C语言的标准库函数中很多地方就采用了回调函数来让用户定制处理过E。如常用的快速排序函数、二分搜索函数等?
快速排序函数原型:
|
其中fcmp是一个回调函数的变量?
下面l出一个具体的例子Q?
|
2.4 面向对象语言中的回调QDelphiQ?
Dephi与C++一PZ保持与过E语aPascal的兼Ҏ,它在引入面向对象机制的同Ӟ保留了以前的l构化特性。因此,对回调的实现Q也有两U截然不同的模式Q一U是l构化的函数回调模式Q一U是面向对象的接口模式?
2.4.1 回调函数
回调函数cd定义Q?
|
按照回调函数的格式自定义函数的实玎ͼ?/P>
|
回调的?/P>
|
下面Q我们就可以在我们的E序里按照需要调用这两个函数?/P>
|
2.4.2 回调对象
什么叫回调对象呢,它具体用在哪些场合?首先Q让我们把它与回调函数对比一下,回调函数是一个定义了函数的原型,函数体则交由W三Ҏ实现的一U动态应用模式。要实现一个回调函敎ͼ我们必须明确知道几点Q该函数需要那些参敎ͼq回什么类型的倹{同P一个回调对象也是一个定义了对象接口Q但是没有具体实现的抽象c(x口)。要实现一个回调对象,我们必须知道Q它需要实现哪些方法,每个Ҏ中有哪些参数Q该Ҏ需要放回什么倹{?
因此Q在回调对象q种应用模式中,我们会用到接口。接口可以理解成一个定义好了但是没有实现的c,它只能通过l承的方式被别的cd现。Delphi中的接口和COM接口cMQ所有的接口都承与IInterfaceQ等同于IUnknowQ,q且要实C个基本的ҎQueryInterface, _AddRef, 和_Release?
|
|
|
如果传入的对象ؓTRectQ那么画矩ŞQ如果ؓTRoundQ那么就为圆形。用户也可以按照自己的意图来实现IShape接口Q画q囑ŞQ?
|
2.4.3 回调Ҏ
回调Ҏ(Callback Method)可以看作是回调对象的一部分QDelphi对windows消息的封装就采用了回调方法这个概c在有些场合Q我们不需要按照给定的要求实现整个对象Q而只要实现其中的一个方法就可以了,q是我们׃用到回调Ҏ?
回调Ҏ的定义如下:
|
TNotifyEvent 是Delphi中最常用的回调方法,H体、控件的很多事gQ如单击事g、关闭事件等都是采用了TnotifyEvent。回调方法的变量一般通过事g属性的方式来定义,如TCustomForm的创Z件的定义Q?
|
我们通过l事件属性变量赋值就可以定制事g处理器?/P>
用户定义对象Q包含回调方法的对象Q:
|
H体对象Q?/P>
|
使用ҎQ?/P>
|
3.1 回调接口模型
CORBA的消息传递机制有很多U,比如回调接口、事件服务和通知服务{。回调接口的原理很简单,CORBA客户和服务器都具有双重角Ԍ卛_当服务器也是客户客户?
回调接口的反向调用与正向调用往往是同时进行的Q如果服务端多次调用该回调接口,那么q个回调接口变成异步接口了。因此,回调接口在CORBA中常常充当事件注册的用途,客户端调用该注册函数Ӟ客户函数是回调函数Q在此后的调用中Q由于不需要客L的主动参与,该函数就是实C一U异步机制?
从CORBA规范我们知道Q一个CORBA接口在服务端和客L有不同的表现形式Q在客户端一般用桩QStubQ文Ӟ服务端则用到框架QSkeletonQ文Ӟ接口的规格采用IDL来定义。而回调函数的引入Q得服务端和客L都需要实C定的桩和框架。下面是回调接口的实现模型:
下面l出了一个用回调的接口文gQ服务端需要实现Server接口的框Ӟ客户端需要实现CallBack的框Ӟ
|
客户端首先通过同步方式调用服务端的接口RegistCBQ用来注册回调接口CallBack。服务端收到该请求以后,׃保留该接口引用,如果发生某种事g需要向客户端通知的时候就通过该引用调用客h的OnEvent函数Q以便对方及时处理?nbsp;
from gushizuozhe
load data infile "zuozhe.txt" into table gushizuozhe fields optionally enclosed by '\"' terminated by
',' (ID,name,zi,hao);
grant select on *.* to "public@192.168.%" identified by 'public';
revoke select on *.* from "public@192.168.%"
revoke q不能删除用Pdelete from mysql.user where user like "public%"
flush flush_option[,flush_option]
kill thread_id unix/linux下进?BR>show processlist
select user()
set password for www@localhost=password("www")
set option_setting
写锁、读?BR>lock tables gushi write,gushizuozhe write;
unlock tables
MYSQL~程接口
MYSQL C API
1、数据类?BR>1)my_ulonglong
2)my_bool
3)MYSQL_FIELD_OFFSET
4)MYSQL
5)MYSQL_RES
6)MYSQL_ROW
7)MYSQL_FIELD
{
char *name;
char *table;
char *def;
enum enum_field_types type;//列的数据cd
unsigned int length;//列定义的长度
unsigned int max_length;//数据实际的最大长?BR>unsigned int flags;//列的属?BR>}
8)unsigned int decimals//数位数
2、函?BR>1)my_bool mysql_change_user(MYSQL *mysql,const char *user,const char *password,const char *db)
2)void mysql_close(MYSQL *mysql)
3)MYSQL *mysql_init(MYSQL *mysql)
4)int mysql_option(MYSQL *mysql,enum mysql_option,const char *arg)指定更精的q接参数选项
5)int mysql_ping(MYSQL *mysql)//查连接是否正?BR>6)MYSQL *mysql_real_connect(MYSQL *mysql,const char *host,const char *user,const char *password,const
char *db,unsiged int port,const char *unix_socket,unsigned int client_flag)
7)int mysql_select_db(MYSQL *mysql,const char *db)//选择数据库db为当前数据库
8)int mysql_query(MYSQL *mysql,const char *query)
9)int mysql_real_query(MYSQL *mysql,const char *query,unsigned int length)
10)char *mysql_info(MYSQL *mysql)//q回最后执行的一ơ操作的有关信息?BR>11)MYSQL_RES *mysql_store_result(MYSQL *mysql)//d一个查询的全部l果?BR>12)MYSQL_RES *mysql_use_result(MYSQL *mysql)//初始化一个结果集Q但是不把结果读到客LQ仍然保留在服务?/P>
?BR>13)void mysql_free_result(MYSQL_RES *result)//释放l果集用的内存?BR>14)my_ulonglong mysql_affected_rows(MYSQL *mysql)//q回最后一个update,delete,insert操作影响的记录数?BR>15)my_ulonglong mysql_num_rows(MYSQL *mysql)//mysql_store_result()q回的结果集中的记录数?BR>16)MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES *result,MYSQL_ROW_OFFSET offset)
17)MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES *result)//当前光标位置
18)MYSQL_ROW_OFFSET mysql_data_seek(MYSQL_RES *result,unsigned long long offset)
19)MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)//l果集中的下一条记?BR>20)unsigned int mysql_fetch_lengths(MYSQL_RES *result)//l果集中当前记录的长?BR>21)unsigned int mysql_num_fields(MYSQL_RES *result)//l果集中列的数目
22)MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result,MYSQL_FIELD_OFFSET offset)
23)MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RES *result)//当前光标位置
24)MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result)//l果集中当前列信?BR>25)MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *result)//l果集中所有列信息
26)MYSQL_RES *mysql_list_dbs(MYSQL *mysql,const char *wild)//与wild正则表达式匹配的数据库信?BR>27)MYSQL_RES *mysql_list_tables(MYSQL *mysql,const char *wild)//与wild正则表达式匹配的表信?BR>28)MYSQL_RES *mysql_list_fields(MYSQL *mysql,const char * table,const char *wild)//与当前表Q匹配wild?/P>
则表辑ּ的所有列名的l果?BR>29)MYSQL_RES *mysql_list_processes(MYSQL *mysql)
30)char *mysql_stat(MYSQL *mysql)//当前服务器的信息
31)char *mysql_get_server_info(MYSQL *mysql)
32)char *mysql_get_client_info(MYSQL *mysql)
33)char *mysql_get_host_info(MYSQL *mysql)
34)char *mysql_get_proto_info(MYSQL *mysql)
35)unsiged long mysql_thread_id(MYSQL *mysql)
36)int mysql_kill(MYSQL *mysql,unsiged long pid)
37)int mysql_shutdown(MYSQL *mysql)
38)void mysql_debug(char *debug)
39)int mysql_dump_debug_info(char *debug)
40)unsigned int mysql_errno(MYSQL *mysql)
41)char *mysql_error(MYSQL *mysql)
得到工具栏尺?BR>CSize sizeBar;
CToolBar m_wndToolBar;
m_wndToolBar.GetToolBarCtrl().GetMaxSize(&sizeBar);
在工h上添加编辑框
CRect rect;
m_wndToolBar.SetButtonInfo(9,ID_SEPARATOR,TBBS_SEPARATOR,100);
m_wndToolBar.GetItemRect(9,&rect);
m_wndComboBox.Create(CBS_DROPDOWN|WS_VISIBLE|WS_VSCROLL|CBS_AUTOHSCROLL,rect, &m_wndToolBar,105);
格式化一D|代码
Alt+F8
定位预处?ifQ?endif
Ctrl+K
层H口的实?BR>在PreCreateWindow()中加?BR>cs.dwExStyle=WS_EX_TOPMOST