---
#1.流程
首先建立socket:
m_hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
***绑定窗口:***
iErrorCode = WSAAsyncSelect(m_hSocket, m_hWnd, WM_SOCKET_NOTIFY, FD_READ | FD_CONNECT | FD_CLOSE);//WM_SOCKET_NOTIFY用来接受网络返回消息
ON_MESSAGE(WM_SOCKET_NOTIFY, OnSocketNotify)//通过这个接受网络消息并跳转函数
***//SOCKET 消息处理程序***
LRESULT CTCPSocket::OnSocketNotify(WPARAM wParam, LPARAM lParam)
{
switch (WSAGETSELECTEVENT(lParam))
{
case FD_CONNECT: //网络连接
{
return OnSocketNotifyConnect(wParam, lParam);
}
case FD_READ: //数据读取
{
return OnSocketNotifyRead(wParam, lParam);
}
case FD_CLOSE: //网络关闭
{
return OnSocketNotifyClose(wParam, lParam);
}
}
return 0;
}
***//处理网络连接事件***
LRESULT CTCPSocket::OnSocketNotifyConnect(WPARAM wParam, LPARAM lParam)
{
//判断状态
int iErrorCode = WSAGETSELECTERROR(lParam);
if (iErrorCode == 0) m_cbSocketStatus = SOCKET_STATUS_CONNECT;
else CloseSocket(SHUT_REASON_TIME_OUT);
//发送通知
m_pITCPSocketSink->OnEventTCPSocketLink(GetSocketID(), GetLastError());
return 1;
}
//对m_pITCPSocketSink解释
//在外部定义网络接口
interface ITCPSocketSink : public IUnknownEx
{
public:
//连接事件
virtual bool __cdecl OnEventTCPSocketLink(WORD wSocketID, INT nErrorCode)=NULL;
//关闭事件
virtual bool __cdecl OnEventTCPSocketShut(WORD wSocketID, BYTE cbShutReason)=NULL;
//读取事件
virtual bool __cdecl OnEventTCPSocketRead(WORD wSocketID, CMD_Command Command, VOID * pData, WORD wDataSize)=NULL;
};
然后在内部定义成员变量:
ITCPSocketSink * m_pITCPSocketSink; //回调接口
接着其它类引用此接口文件
//游戏广场
class CPlazaViewItem :public ITCPSocketSink
{
CTCPSocketHelper m_ClientSocket; //网络连接
//连接事件
virtual bool __cdecl OnEventTCPSocketLink(WORD wSocketID, INT nErrorCode);//子类中实现接口,并做一些相应的处理, 比如发送消息等
}
CTCPsocketHelper定义转到:
DECLARE_MODULE_HELPER(TCPSocket,NETWORK_SERVICE_DLL_NAME,"CreateTCPSocket")
DECLARE_MODULE_HELPER定义转到:
//组件辅助类宏
#define DECLARE_MODULE_HELPER(OBJECT_NAME,MODULE_DLL_NAME,CREATE_FUNCTION_NAME) \
class C##OBJECT_NAME##Helper : public CTempldateHelper<I##OBJECT_NAME> \
{ \
public: \
C##OBJECT_NAME##Helper() : CTempldateHelper<I##OBJECT_NAME>(IID_I##OBJECT_NAME, \
VER_I##OBJECT_NAME,MODULE_DLL_NAME,CREATE_FUNCTION_NAME) { } \
};
//cpp中对接口进行具体实现
bool __cdecl CPlazaViewItem::OnEventTCPSocketLink(WORD wSocketID, INT nErrorCode)
{
m_DlgLogon.SendLogonPacket(m_ClientSocket.GetInterface());//此处发包
}
CDlgLogon m_DlgLogon; //登录对话框
//跳转到发包对话框类,发包
bool CDlgLogon::SendLogonPacket(ITCPSocket * pIClientSocke)
{
pIClientSocke->SendData(MDM_GP_LOGON,SUB_GP_LOGON_ACCOUNTS,cbBuffer,sizeof(CMD_GP_LogonByAccounts)+Packet.GetDataSize());
}
//跳转到TCPSocket.cpp函数的SendData()函数,经过SendDataBuffer()转换,调用底层的send函数发送信息
send(m_hSocket, (char *)pBuffer + wSended, wSendSize - wSended, 0);
---
***//处理网络读取消息***
LRESULT CTCPSocket::OnSocketNotifyRead(WPARAM wParam, LPARAM lParam)
{
recv(m_hSocket, (char *)m_cbRecvBuf + m_wRecvSize, sizeof(m_cbRecvBuf) - m_wRecvSize, 0);//recv接收函数
m_pITCPSocketSink->OnEventTCPSocketRead(GetSocketID(), Command, pDataBuffer, wDataSize);//处理函数,此接口函数调用到子类处理
}
//例如游戏广场 //网络读取消息
bool __cdecl CPlazaViewItem::OnEventTCPSocketRead(WORD wSocketID, CMD_Command Command, VOID * pData, WORD wDataSize)
{
switch (Command.wMainCmdID)
{
case MDM_GP_LOGON: //登录消息
{
return OnSocketMainLogon(Command,pData,wDataSize);
}
case MDM_GP_SERVER_LIST: //列表消息
{
return OnSocketMainServerList(Command,pData,wDataSize);
}
case MDM_GP_SYSTEM: //系统消息
{
return OnSocketMainSystem(Command,pData,wDataSize);
}
case MDM_GP_USER: //用户消息
{
return OnSocketMainUser(Command,pData,wDataSize);
}
}
return true;
}
---
至此发现,在网络模型CTCPSocket中,用到了关键:接口模型,通过接口这一模型帮助,避免了直接调用子类,最大限度解耦了关系。当子类需要用到此网络模型时,只需要引用此接口,然后实现它,并在成员变量中声明它便可方便灵活使用了。
---
#1.流程
首先建立socket:
m_hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
***绑定窗口:***
iErrorCode = WSAAsyncSelect(m_hSocket, m_hWnd, WM_SOCKET_NOTIFY, FD_READ | FD_CONNECT | FD_CLOSE);//WM_SOCKET_NOTIFY用来接受网络返回消息
ON_MESSAGE(WM_SOCKET_NOTIFY, OnSocketNotify)//通过这个接受网络消息并跳转函数
***//SOCKET 消息处理程序***
LRESULT CTCPSocket::OnSocketNotify(WPARAM wParam, LPARAM lParam)
{
switch (WSAGETSELECTEVENT(lParam))
{
case FD_CONNECT: //网络连接
{
return OnSocketNotifyConnect(wParam, lParam);
}
case FD_READ: //数据读取
{
return OnSocketNotifyRead(wParam, lParam);
}
case FD_CLOSE: //网络关闭
{
return OnSocketNotifyClose(wParam, lParam);
}
}
return 0;
}
***//处理网络连接事件***
LRESULT CTCPSocket::OnSocketNotifyConnect(WPARAM wParam, LPARAM lParam)
{
//判断状态
int iErrorCode = WSAGETSELECTERROR(lParam);
if (iErrorCode == 0) m_cbSocketStatus = SOCKET_STATUS_CONNECT;
else CloseSocket(SHUT_REASON_TIME_OUT);
//发送通知
m_pITCPSocketSink->OnEventTCPSocketLink(GetSocketID(), GetLastError());
return 1;
}
//对m_pITCPSocketSink解释
//在外部定义网络接口
interface ITCPSocketSink : public IUnknownEx
{
public:
//连接事件
virtual bool __cdecl OnEventTCPSocketLink(WORD wSocketID, INT nErrorCode)=NULL;
//关闭事件
virtual bool __cdecl OnEventTCPSocketShut(WORD wSocketID, BYTE cbShutReason)=NULL;
//读取事件
virtual bool __cdecl OnEventTCPSocketRead(WORD wSocketID, CMD_Command Command, VOID * pData, WORD wDataSize)=NULL;
};
然后在内部定义成员变量:
ITCPSocketSink * m_pITCPSocketSink; //回调接口
接着其它类引用此接口文件
//游戏广场
class CPlazaViewItem :public ITCPSocketSink
{
CTCPSocketHelper m_ClientSocket; //网络连接
//连接事件
virtual bool __cdecl OnEventTCPSocketLink(WORD wSocketID, INT nErrorCode);//子类中实现接口,并做一些相应的处理, 比如发送消息等
}
CTCPsocketHelper定义转到:
DECLARE_MODULE_HELPER(TCPSocket,NETWORK_SERVICE_DLL_NAME,"CreateTCPSocket")
DECLARE_MODULE_HELPER定义转到:
//组件辅助类宏
#define DECLARE_MODULE_HELPER(OBJECT_NAME,MODULE_DLL_NAME,CREATE_FUNCTION_NAME) \
class C##OBJECT_NAME##Helper : public CTempldateHelper<I##OBJECT_NAME> \
{ \
public: \
C##OBJECT_NAME##Helper() : CTempldateHelper<I##OBJECT_NAME>(IID_I##OBJECT_NAME, \
VER_I##OBJECT_NAME,MODULE_DLL_NAME,CREATE_FUNCTION_NAME) { } \
};
//cpp中对接口进行具体实现
bool __cdecl CPlazaViewItem::OnEventTCPSocketLink(WORD wSocketID, INT nErrorCode)
{
m_DlgLogon.SendLogonPacket(m_ClientSocket.GetInterface());//此处发包
}
CDlgLogon m_DlgLogon; //登录对话框
//跳转到发包对话框类,发包
bool CDlgLogon::SendLogonPacket(ITCPSocket * pIClientSocke)
{
pIClientSocke->SendData(MDM_GP_LOGON,SUB_GP_LOGON_ACCOUNTS,cbBuffer,sizeof(CMD_GP_LogonByAccounts)+Packet.GetDataSize());
}
//跳转到TCPSocket.cpp函数的SendData()函数,经过SendDataBuffer()转换,调用底层的send函数发送信息
send(m_hSocket, (char *)pBuffer + wSended, wSendSize - wSended, 0);
---
***//处理网络读取消息***
LRESULT CTCPSocket::OnSocketNotifyRead(WPARAM wParam, LPARAM lParam)
{
recv(m_hSocket, (char *)m_cbRecvBuf + m_wRecvSize, sizeof(m_cbRecvBuf) - m_wRecvSize, 0);//recv接收函数
m_pITCPSocketSink->OnEventTCPSocketRead(GetSocketID(), Command, pDataBuffer, wDataSize);//处理函数,此接口函数调用到子类处理
}
//例如游戏广场 //网络读取消息
bool __cdecl CPlazaViewItem::OnEventTCPSocketRead(WORD wSocketID, CMD_Command Command, VOID * pData, WORD wDataSize)
{
switch (Command.wMainCmdID)
{
case MDM_GP_LOGON: //登录消息
{
return OnSocketMainLogon(Command,pData,wDataSize);
}
case MDM_GP_SERVER_LIST: //列表消息
{
return OnSocketMainServerList(Command,pData,wDataSize);
}
case MDM_GP_SYSTEM: //系统消息
{
return OnSocketMainSystem(Command,pData,wDataSize);
}
case MDM_GP_USER: //用户消息
{
return OnSocketMainUser(Command,pData,wDataSize);
}
}
return true;
}
---
至此发现,在网络模型CTCPSocket中,用到了关键:接口模型,通过接口这一模型帮助,避免了直接调用子类,最大限度解耦了关系。当子类需要用到此网络模型时,只需要引用此接口,然后实现它,并在成员变量中声明它便可方便灵活使用了。
---