在上一篇中,先介绍了整个框架的类图。
下面拿WINDOW 的6个IO模型进行演练,对WIN 6种SOCKET IO模型不了解的建议大家网上搜一下,有好多老陈和女儿通信的幽默描述。我这里就不再说解,直接贴码。
socketSelectAccept.h
/********************************************************************
创建时间: 2013/04/05
文件名: socketSelectAccept.h
描述:
SOCKET I/O 模式 一 阻塞方式 (select),主要实现了阻塞
方式的I/O工作模式。
作者: fengsh
QQ : 19985430
电子邮件: fengsh998@163.com
Blog : http://blog.csdn.net/fengsh998
@CopyRight fengsh
*********************************************************************/
#pragma once
#include "socketBase.h"
#include "string"
class CSocketSelect :
public CSocketBase
{
private:
void destroySocket();
void stopthread();
void disconnect();
public:
CSocketSelect(void);
~CSocketSelect(void);
int startServer();
int stopServer();
bool sendtext(const std::string& content);
void checkRecvicedMessage();
SOCKET dataSocket;
bool isexit;
private:
void * acceptid;
void * recvid;
};
#include "socketSelectAccept.h"
#include "SocketConst.h"
#include "socketServerCallback.h"
#include "socketThread.h"
static void* appcet_thread(void* param);
static void* recv_thread(void* param);
CSocketSelect::CSocketSelect(void):isexit(false)
{
dataSocket = NULL;
}
CSocketSelect::~CSocketSelect(void)
{
//先将CALLBACK空置,防止线程回调到的界面已DELETE
m_scallback = NULL;
disconnect();
destroySocket();
isexit = true;
stopthread();
dataSocket = NULL;
}
void CSocketSelect::destroySocket()
{
closesocket(m_listenSocket);
WSACleanup();
m_listenSocket = NULL;
}
void CSocketSelect::stopthread()
{
socket_thread_join(&acceptid);
socket_thread_join(&recvid);
acceptid = 0;
recvid = 0;
}
int CSocketSelect::startServer()
{
if (initSocket())
{
//创建检查ACCEPT线程
socket_thread_create(&this->acceptid,appcet_thread,(void*)this);
//创建不断查询消息线程
isexit = false;
checkRecvicedMessage();
return 1;
}
return -1;
}
void CSocketSelect::disconnect()
{
if (dataSocket)
{
closesocket(dataSocket);
dataSocket = NULL;
}
}
int CSocketSelect::stopServer()
{
bool closeYes = true;
if (m_scallback)
{
closeYes = dispatchcallback(cbServerClose,NULL);
}
if (closeYes)
{
isexit = true;
disconnect();
destroySocket();
stopthread();
dataSocket = NULL;
}
return 1;
}
bool CSocketSelect::sendtext( const std::string& content )
{
return sendData(dataSocket,content);
}
void CSocketSelect::checkRecvicedMessage()
{
socket_thread_create(&this->recvid,recv_thread,(void*)this);
}
//不停的进行查询是否有消息到来,耗U
//这里就是所谓的阻塞,不能去做其它事情了。
static void* recv_thread(void* param)
{
if (!param)
{
return 0;
}
DISPATCHPARAM dp;
char recvBuf[1024]={0};
CSocketSelect *ss = (CSocketSelect*)param;
while (1)
{
if (ss->isexit)
{
break;
}
memset(&dp,0,sizeof(DISPATCHPARAM));
socket_thread_sleep(500);
if (ss->dataSocket)
{
//每次都来查询有否消息。
ss->dispatchcallback(cbReadyRev,NULL);
int nRetSize=recv(ss->dataSocket,recvBuf,1024,0);
if (nRetSize>0)
{
strcpy(dp.msg,recvBuf);
//回调到界面
ss->dispatchcallback(cbCommunication,&dp);
//回调到接收完成
ss->dispatchcallback(cbRecviced,NULL);
}
else if (nRetSize == 0)
{//客户端主动断连了。0
ss->dataSocket = NULL;
dp.errcode = WSAGetLastError();
ss->dispatchcallback(cbDisconnect,&dp);
}
else if (nRetSize == -1)
{
//客户端异常断开10054 当客户端在监听recv动作时被关闭了socket就会引发
//10053 服务器主动断开
//10093 在没有任何客户端连接的情况下,服务器关闭数据SOCKET引发
ss->dataSocket = NULL;
strcpy(dp.errmsg,"client error.");
dp.errcode = WSAGetLastError();
ss->dispatchcallback(cbDisconnect,&dp);
}
}
}
return 0;
}
//阻塞等待客户端的连接。
static void* appcet_thread(void* param)
{
CSocketSelect * ss = (CSocketSelect*)param;
int nConNum=0;
DISPATCHPARAM dp;
memset(&dp,0,sizeof(DISPATCHPARAM));
char hint[1024]={0};
while(true)
{
SOCKADDR_IN addrClient;
int addrClientSize=sizeof(SOCKADDR_IN);
ss->dataSocket = accept(ss->m_listenSocket,(struct sockaddr*)&addrClient,&addrClientSize);
if (ss->dataSocket==INVALID_SOCKET)
{
ss->dataSocket = NULL;
if (ss->checkSocketError(WSAGetLastError()))
{
break;
}
continue;
}
else
{
nConNum++;
strcpy(dp.info.ip,inet_ntoa(addrClient.sin_addr));
dp.info.port = addrClient.sin_port;
strcpy(dp.msg,hint);
ss->dispatchcallback(cbHasConnect,&dp);
}
}
return 0;
}