CAsyncSocket介绍:它是一个异步非阻塞Socket封装类。它的工作原理是建立在MFC消息系统上,收到一个消息后会回调一个相应的函数。
一、原理分析
1、一般情况是要新建一类然后继承它,这样才可以重载它的一些函数。
2、服务端和客户端都用Create来新建一个Socket,不同的是服务端要设置IP和端口,客户端新建时只设置IP。
3、服务端一般不用Bind,直接Listen就可以了。当服务端进入监听后,客户端向服务端发一个Connect就可以了。注意IP地址和端口,特别是本机。
4、服务端收到Connect后会响应OnAccept函数(它里面怎样写见后面),批准客户端连接用Accept。
5、客户端收到Accept会响应OnConnect函数。之后服务端和客户端就会进入消息等待状态。
6、一方的Send会激活对方的OnReceive。
7、当数据未完全发送或接收时会响应OnSend或OnReceive。
8、关闭时会激活OnClose。
二、与窗口类的互动
当响应OnReceive后,就可以在OnReceive里面用Receive接收数据。但问题来了,怎样把收到的数据传给窗口类呢(如CDialog或CView)?我的解决方法是用自定义消息,在类里建一个句柄变量,构建的时候让它指向窗口类的句柄。在响应OnReceive时,用SendMessage向句柄发一个自定义消息。然后在窗口类里响应这个自定义消息就可以了。
PS:自定义消息
三、源码
头文件:
#if !defined(AFX_GMSOCKET_H__84048A8F_A38B_4107_9811_F279292BA3B3__INCLUDED_)
#define AFX_GMSOCKET_H__84048A8F_A38B_4107_9811_F279292BA3B3__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// GMSocket.h : header file
//
/
// GMSocket command target
#define WM_SOCKET_OnAccept WM_USER+1000
#define WM_SOCKET_OnClose WM_USER+1001
#define WM_SOCKET_OnConnect WM_USER+1002
#define WM_SOCKET_OnOutOfBandData WM_USER+1003
#define WM_SOCKET_OnReceive WM_USER+1004
#define WM_SOCKET_OnSend WM_USER+1005
class GMSocket : public CAsyncSocket
{
// Attributes
public:
// Operations
public:
GMSocket();
GMSocket(HWND hwnd);
virtual ~GMSocket();
// Overrides
public:
void ShowErrorMsg(int errorcode);
HWND SetTargetHWND(HWND hwnd);
HWND m_TargetWnd;
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(GMSocket)
public:
virtual void OnAccept(int nErrorCode);
virtual void OnClose(int nErrorCode);
virtual void OnConnect(int nErrorCode);
virtual void OnOutOfBandData(int nErrorCode);
virtual void OnReceive(int nErrorCode);
virtual void OnSend(int nErrorCode);
//}}AFX_VIRTUAL
// Generated message map functions
//{{AFX_MSG(GMSocket)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
// Implementation
protected:
};
/
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_GMSOCKET_H__84048A8F_A38B_4107_9811_F279292BA3B3__INCLUDED_)
CPP文件:
// GMSocket.cpp : implementation file
//
#include "stdafx.h"
//#include <windows.h>
#include "MyAsyncSocket.h"
#include "GMSocket.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/
// GMSocket
GMSocket::GMSocket()
{
m_TargetWnd=0;
}
GMSocket::GMSocket(HWND hwnd)
{
m_TargetWnd=hwnd;
}
GMSocket::~GMSocket()
{
}
// Do not edit the following lines, which are needed by ClassWizard.
#if 0
BEGIN_MESSAGE_MAP(GMSocket, CAsyncSocket)
//{{AFX_MSG_MAP(GMSocket)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif // 0
/
// GMSocket member functions
void GMSocket::OnAccept(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
if (nErrorCode==0)
{
SendMessage(m_TargetWnd,WM_SOCKET_OnAccept,0,0);
}
else
{
ShowErrorMsg(GetLastError());
}
CAsyncSocket::OnAccept(nErrorCode);
}
void GMSocket::OnClose(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
if (nErrorCode==0)
{
SendMessage(m_TargetWnd,WM_SOCKET_OnClose,0,0);
}
else
{
ShowErrorMsg(GetLastError());
}
CAsyncSocket::OnClose(nErrorCode);
}
void GMSocket::OnConnect(int nErrorCode)
{//OnConnect(WPARAM wParam, LPARAM lParam)
// TODO: Add your specialized code here and/or call the base class
if (nErrorCode==0)
{
SendMessage(m_TargetWnd,WM_SOCKET_OnConnect,0,0);
}
else
{
ShowErrorMsg(GetLastError());
}
CAsyncSocket::OnConnect(nErrorCode);
}
void GMSocket::OnOutOfBandData(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
if (nErrorCode==0)
{
SendMessage(m_TargetWnd,WM_SOCKET_OnOutOfBandData,0,0);
}
else
{
ShowErrorMsg(GetLastError());
}
CAsyncSocket::OnOutOfBandData(nErrorCode);
}
void GMSocket::OnReceive(int nErrorCode)
{//OnReceive(WPARAM wParam, LPARAM lParam)
if (nErrorCode==0)
{
SendMessage(m_TargetWnd,WM_SOCKET_OnReceive,0,0);
}
else
{
ShowErrorMsg(GetLastError());
}
CAsyncSocket::OnReceive(nErrorCode);
}
void GMSocket::OnSend(int nErrorCode)
{
// TODO: Add your specialized code here and/or call the base class
if (nErrorCode==0)
{
SendMessage(m_TargetWnd,WM_SOCKET_OnSend,0,0);
}
else
{
ShowErrorMsg(GetLastError());
}
CAsyncSocket::OnSend(nErrorCode);
}
HWND GMSocket::SetTargetHWND(HWND hwnd)
{
m_TargetWnd=hwnd;
return m_TargetWnd;
}
void GMSocket::ShowErrorMsg(int errorcode)
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
errorcode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
// Free the buffer.
LocalFree( lpMsgBuf );
}