24,854
社区成员
发帖
与我相关
我的任务
分享
class SelectModelServer
{
public:
SelectModelServer(ReceiveAble& receiver);
~SelectModelServer();
private:
int m_nCurrentConCount;
SOCKET m_serverSocket;
SOCKET m_socketArray[FD_SETSIZE];
//bool m_bUseableArray[FD_SETSIZE];
//sockaddr_in peerAddrs[MAXIMUM_WAIT_OBJECTS];
ReceiveAble* m_pReceiver;
private:
void onAccept();
void onReceive(SOCKET& clientSocket);
void onClose(SOCKET& clientSocket);
public:
void init(unsigned short port);
void startServer();
void closeServer();
void close(const SOCKET& socket);
};
#endif
#include "SelectModelServer.h"
#include "ReceiveAble.h"
#pragma comment(lib,"ws2_32.lib")
SelectModelServer::SelectModelServer(ReceiveAble& receiver)
{
this->m_pReceiver=&receiver;
m_nCurrentConCount=0;
/*for (int i=0;i<FD_SETSIZE;i++)
{
m_bUseableArray[i]=true;
}*/
for (int i=0;i<FD_SETSIZE;i++)
{
m_socketArray[i]=INVALID_SOCKET;
}
}
SelectModelServer::~SelectModelServer()
{
closeServer();
}
void SelectModelServer::init(unsigned short port)
{
cout<<"init server(port:"<<port<<")..."<<endl;
if(m_nCurrentConCount!=0)
return;
//1.初始化环境
SocketTools::initSocketContext();
//2.创建套接字
m_serverSocket=socket(AF_INET,SOCK_STREAM,0);
if(m_serverSocket<0)
throw SocketException(WSAGetLastError(),"创建服务套接字失败");
//3.绑定本地ip和端口
sockaddr_in local_addr;
int length =sizeof(sockaddr_in);
memset(&local_addr,0,length);
local_addr.sin_family=AF_INET;
local_addr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//htonl(inet_addr("127.0.0.1"));
local_addr.sin_port=htons(port);
if(bind(m_serverSocket,(struct sockaddr*)&local_addr,length) == SOCKET_ERROR)
throw SocketException(WSAGetLastError(),"绑定失败");
//4.侦听端口
if(listen(m_serverSocket,SOMAXCONN)== SOCKET_ERROR)
throw SocketException(WSAGetLastError(),"侦听失败");
//5.设置非阻塞
unsigned long nonBlock=1;
if(ioctl(m_serverSocket,FIONBIO,&nonBlock)==SOCKET_ERROR)
throw SocketException(WSAGetLastError(),"设置为非阻塞失败");
//6.加入集合
this->m_socketArray[0]=m_serverSocket;
m_nCurrentConCount++;
}
void SelectModelServer::startServer()
{
cout<<("star server success.\n");
int nReturn,i;
struct timeval timeDelay;
timeDelay.tv_sec=0;
timeDelay.tv_usec=1000*10;
fd_set readFdSet;
while (true)
{
FD_ZERO(&readFdSet);
for (i = 0; i <FD_SETSIZE; i++)// m_nCurrentConCount
{
if(m_socketArray[i]!=INVALID_SOCKET)
FD_SET(this->m_socketArray[i],&readFdSet);
}
nReturn=select(0,&readFdSet,NULL,NULL,&timeDelay);//返回 大于0--有效数 等于0--超时 小于0--异常
if(nReturn==0)//超时
{
if(timeDelay.tv_usec<1000*1000)//1秒
timeDelay.tv_usec+=10;//增加0.01毫秒
continue;
}
else if(nReturn==SOCKET_ERROR)
{
cout<<"select error:"<<SocketTools::getWinsockErrorMsg(::WSAGetLastError())<<endl;
continue;
}
if(timeDelay.tv_usec>1000*2)//不超时时,若延时大于2毫秒则减少
{
timeDelay.tv_usec-=1000;//减少1000微秒
}
#ifdef _DEBUG_TIME
{
//正常
printf("select sleep time:%d usecond\n",timeDelay.tv_usec);
}
#endif
//如何判断对方关闭
for (i=0;i<FD_SETSIZE;i++)
{
if (FD_ISSET(m_socketArray[i], &readFdSet))
{
if(i==0)
onAccept();
else
onReceive(m_socketArray[i]);
}
}
}
}
void SelectModelServer::closeServer()
{
//7.关闭服务套接字
closesocket(m_serverSocket);
//8.清除环境
SocketTools::cleanUpSocketContext();
}
void SelectModelServer::onAccept()
{
//5.接收连接
sockaddr_in peerAddr;
int length=sizeof(sockaddr);
//clientSocket=accept(m_serverSocket,(struct sockaddr*)(peerAddrs+m_nCurrentConCount),&length);
SOCKET clientSocket=accept(m_serverSocket,(struct sockaddr*)(&peerAddr),&length);
if(clientSocket==INVALID_SOCKET)
{
printf("accept error\n");
return;
}
//连接达到上限
if(m_nCurrentConCount>=FD_SETSIZE-1)
{
closesocket(clientSocket);
printf("reached max con:%d\n",m_nCurrentConCount);
return;
}
//数组前面的某个socket关闭了
if(m_socketArray[m_nCurrentConCount]!=INVALID_SOCKET)
{
int i;
for(i=0;i<m_nCurrentConCount;i++)
{
if(m_socketArray[i]==INVALID_SOCKET)
{
m_socketArray[i]=clientSocket;
break;
}
}
if(i==m_nCurrentConCount)//异常
{
printf("error when deal with con:%d\n",m_nCurrentConCount);
closesocket(clientSocket);
return;
}
}
else
{
this->m_socketArray[m_nCurrentConCount]=clientSocket;
}
//增加一个连接
{
m_pReceiver->addPeerAddr(clientSocket,peerAddr);
m_nCurrentConCount++;
}
}
void SelectModelServer::onReceive(SOCKET& clientSocket)
{
//6.接收信息
/*
char buf[1024];
int length=recv(clientSocket,buf,sizeof(buf),0);
if(length<=0 || strcmp(buf,"exit")==0)
{
printf("\n error\n");
onClose(clientSocket);
return;
}
buf[length]='\0';
printf("收到信息(字节数%d):%s",length,buf);
//*/
unsigned long length=0;
ioctl(clientSocket,FIONREAD,&length);
if(length==0)
{
this->onClose(clientSocket);
return;
}
this->m_pReceiver->onReceive(clientSocket,*this);
}
void SelectModelServer::onClose(SOCKET& clientSocket)
{
if(clientSocket==INVALID_SOCKET)
return;
int n=closesocket(clientSocket);
if(n==SOCKET_ERROR)
{
printf("close socket error\n");
return;
}
m_pReceiver->removePeer(clientSocket);
clientSocket=INVALID_SOCKET;
m_nCurrentConCount--;
}
void SelectModelServer::close(const SOCKET& socket)
{
this->onClose((SOCKET)socket);
}
class MainClass
{
public:
void run(unsigned int port)
{
try{
SocketChanel receiver;//处理数据类
SelectModelServer server(receiver); //监听类,并注入receiver
server.init(port); //初始化端口
server.startServer();//进入select循环
}catch(Exception& e)
{
e.printException();
}
}
};
int main()
{
printf("欢迎使用网络081班点歌系统^-^\n");
printf("请将您的歌曲目录添加到config/dirList.txt里面即可点播.\n");
MainClass mainClass;
mainClass.run(8000);
system("pause");
return 0;
}