sokcetServerBySelect.h
/********************************************************************
创建时间: 2013/04/05
文件名: sokcetServerBySelect.h
描述:
select I/O 主要采用FD_SET,FD_CLR,FD_ISSET,FD_ZERO 宏的运用
来实现I/O 模型
作者: fengsh
QQ : 19985430
电子邮件: fengsh998@163.com
Blog : http://blog.csdn.net/fengsh998
@CopyRight fengsh
*********************************************************************/
#pragma once
#include "socketBase.h"
#define GET_ARRAY_LEN(array,len) {len = (sizeof(array) / sizeof(array[0]));}
typedef enum SelectResult {srNone,srError,srHasRead,srHasWrite};
class CSokcetServerBySelect : public CSocketBase
{
private:
void doWaitClient();
void doSelect();
void waitThreadExit();
void closeClientSockets();
public:
CSokcetServerBySelect(void);
~CSokcetServerBySelect(void);
int startServer();
int stopServer();
bool sendtext(const std::string& content);
//检查是否有数据可读/写
SelectResult listenSelectResult();
void setStop(bool flag);
bool getStop();
SOCKET m_clientArr[FD_SETSIZE];
int m_icount ;
private:
void *waitid;
void *selectid;
bool isStop;
};
sokcetServerBySelect.cpp
#include "sokcetServerBySelect.h"
#include "socketThread.h"
#include "SocketConst.h"
//等待连接线程
static void* wait_client_thread(void *param);
//负责进行查询线程。
static void* select_thread(void* param);
CSokcetServerBySelect::CSokcetServerBySelect(void):waitid(0),selectid(0),m_icount(0),isStop(true)
{
memset(&m_clientArr,0,64*4);//每个数组的指针长度为4,共有64个空间,占有64*4
}
CSokcetServerBySelect::~CSokcetServerBySelect(void)
{
closeClientSockets();
//listen socket free at parent class.eg:closesocket(listensocket);WSACleanup();
}
int CSokcetServerBySelect::startServer()
{
if (initSocket())
{
doWaitClient();
setStop(false);
doSelect();
}
return -1;
}
int CSokcetServerBySelect::stopServer()
{
setStop(true);
closeClientSockets();
closeListenSocket();
waitThreadExit();
return -1;
}
bool CSokcetServerBySelect::sendtext( const std::string& content )
{
//it is demo . don't write the code.
for (int i = 0;i < m_icount;i++ )
{
sendData(m_clientArr[i],content);
}
return true;
}
void CSokcetServerBySelect::waitThreadExit()
{
socket_thread_join(&waitid);
socket_thread_join(&selectid);
waitid = 0;
selectid = 0;
}
void CSokcetServerBySelect::doWaitClient()
{
socket_thread_create(&waitid,wait_client_thread,(void *)this);
}
void CSokcetServerBySelect::doSelect()
{
socket_thread_create(&selectid,select_thread,(void *)this);
}
void CSokcetServerBySelect::closeClientSockets()
{
//int len ;
//GET_ARRAY_LEN(m_clientArr,len);
for (int i = 0 ;i < m_icount; i++)
{
if (m_clientArr[i] != INVALID_SOCKET)
{
closesocket(m_clientArr[i]);
}
}
m_icount = 0;
}
SelectResult CSokcetServerBySelect::listenSelectResult()
{
return srNone;
}
bool CSokcetServerBySelect::getStop()
{
return isStop;
}
void CSokcetServerBySelect::setStop( bool flag )
{
isStop = flag;
}
static void* wait_client_thread(void *param)
{
CSokcetServerBySelect *slt = (CSokcetServerBySelect*)param;
DISPATCHPARAM dp;
memset(&dp,0,sizeof(DISPATCHPARAM));
SOCKET socketClient;
while(TRUE)
{
SOCKADDR_IN addrClient;
int addrClientSize=sizeof(SOCKADDR_IN);
socketClient=accept(slt->m_listenSocket,(struct sockaddr*)&addrClient,&addrClientSize);
if (socketClient==INVALID_SOCKET)
{
socketClient = NULL;
if (slt->checkSocketError(WSAGetLastError()))
{
break;
}
continue;
}
else
{
//to do limit FD_SETSIZE,rang to out szie.
slt->m_clientArr[slt->m_icount++] = socketClient;
strcpy(dp.info.ip,inet_ntoa(addrClient.sin_addr));
dp.info.port = addrClient.sin_port;
slt->dispatchcallback(cbHasConnect,&dp);
}
}
return 0;
}
static void* select_thread(void* param)
{
CSokcetServerBySelect *slt = (CSokcetServerBySelect*)param;
DISPATCHPARAM dp;
memset(&dp,0,sizeof(DISPATCHPARAM));
fd_set fdread,fdwrite;
int ret;
struct timeval tv={1,0};//超时时间设为1秒。如果tv = NULL 则一直等待
//tv.tv_sec = xxx/1000; //秒
//tv.tv_usec = xxxx%1000; //毫秒
char szMessage[BUFFERMAX];
while(true)
{
if (slt->getStop())
{
break;
}
FD_ZERO(&fdread);//将fdread初始化空集 0000 0000
FD_ZERO(&fdwrite);
for (int i = 0;i < slt->m_icount; i++)
{
FD_SET(slt->m_clientArr[i],&fdread);
FD_SET(slt->m_clientArr[i],&fdwrite);
}
/* ERROR CODE;
WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。
WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效。
WSAEINVAL:超时时间值非法。
WSAEINTR:通过一个WSACancelBlockingCall()来取消一个(阻塞的)调用。
WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。
WSAENOTSOCK:描述字集合中包含有非套接口的元素。
*/
ret=select(0,&fdread,&fdwrite,NULL,NULL/*&tv*/);//WINDOWS下第一个参数可以忽略,LINUX下,不能大于1024
if (ret != 0) //-1 or 1
{
for (int i = 0;i < slt->m_icount; i++)
{
if (FD_ISSET(slt->m_clientArr[i],&fdread))
{
ret = recv(slt->m_clientArr[i],szMessage,BUFFERMAX,0);
if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET))
{
closesocket(slt->m_clientArr[i]);
slt->m_clientArr[i--]=slt->m_clientArr[--slt->m_icount];
dp.errcode = WSAGetLastError();
slt->dispatchcallback(cbDisconnect,&dp);
}
else
{
strcpy(dp.msg,szMessage);
//回调到界面
slt->dispatchcallback(cbCommunication,&dp);
//回调到接收完成
slt->dispatchcallback(cbRecviced,NULL);
}
}
if (FD_ISSET(slt->m_clientArr[i],&fdwrite))// 有可写变化
{
}
}
}
}
return 0;
}