cocos2dx Socket(二)

Epoll类

#ifndef __CLIENT_EPOLL_H__
#define __CLIENT_EPOLL_H__

//#include "cocos2d.h"
#include "ClientSocket.h"
#ifdef WIN32
	#include 
#else
#include 
#include 
#endif
//USING_NS_CC;

#define _SOCKET_FD_MAX_	3
#define EVENTMAX	(_SOCKET_FD_MAX_*3)

typedef void (*MY_SOCKET_FD_CALLBACK)(int event,void* buf,int len);

class CMyEpoll
{
public:
	CMyEpoll();
	~CMyEpoll();
public:
	int MyCreateEpoll(void);
	int MyAddSocketFdEvent(int socket_fd, MY_SOCKET_FD_CALLBACK cb);
	int MyDelSocketFdEvent(int socket_fd);
	void RunThread(void);
	void MyRun(float time);
	MY_SOCKET_FD_CALLBACK MyGetSocketFdCallBack(int socket_fd);
public:
	static bool m_exitflag;
	static int m_socket_fd[_SOCKET_FD_MAX_];
	static MY_SOCKET_FD_CALLBACK m_cb[_SOCKET_FD_MAX_];
#ifdef WIN32
	static bool socketConnect[_SOCKET_FD_MAX_];
#endif
	int m_epfd;
};
#endif

#include "ClientEpoll.h"


bool CMyEpoll::m_exitflag = false;
int CMyEpoll::m_socket_fd[_SOCKET_FD_MAX_] = {0};
MY_SOCKET_FD_CALLBACK CMyEpoll::m_cb[_SOCKET_FD_MAX_] ={0};
#ifdef WIN32
bool CMyEpoll::socketConnect[_SOCKET_FD_MAX_] = {0};
#endif
CMyEpoll::CMyEpoll()
{
	m_epfd = -1;
	for( int i = 0; i < _SOCKET_FD_MAX_; i++ )
	{
		CMyEpoll::m_socket_fd[i] = -1;
		CMyEpoll::m_cb[i] = NULL;
	}

	CMyEpoll::m_exitflag = false;
}

CMyEpoll::~CMyEpoll()
{
	CMyEpoll::m_exitflag = true;
	
#ifdef WIN32
#else
	if( m_epfd >= 0 )
		{
			close( m_epfd );
			m_epfd = -1;
		}
#endif
}

//创建socket
int CMyEpoll::MyCreateEpoll(void)
{
#ifdef WIN32 
	return 0;
#else
	/*
	该 函数生成一个epoll专用的文件描述符。它其实是在内核申请一空间,
	用来存放你想关注的socket fd上是否发生以及发生了什么事件。
	size就是你在这个epoll fd上能关注的最大socket fd数。随你定好了。只要你有空间。
	*/
	m_epfd = epoll_create(1024);
	if( m_epfd == -1 )
	{
		return -1;
	}
	return m_epfd;
#endif
}

//handle: sockid
//cb : socket callback fun
int CMyEpoll::MyAddSocketFdEvent(int socket_fd, MY_SOCKET_FD_CALLBACK cb)
{
	for( int i = 0; i < _SOCKET_FD_MAX_; i++ )
	{
		if( CMyEpoll::m_socket_fd[i] == -1 )    //
		{
			CMyEpoll::m_socket_fd[i] = socket_fd;
			CMyEpoll::m_cb[i] = cb;
			#ifdef WIN32
			CMyEpoll::socketConnect[i] = false;
			#endif
			break;
		}
	}
#ifdef WIN32
	return 0;
#else
	struct epoll_event event = {0};
	event.data.fd = socket_fd;
	event.events = (EPOLLIN  | EPOLLOUT);
	
	/*
	该函数用于控制某个epoll文件描述符上的事件,
	可以注册事件,修改事件,删除事件
	*/
	int nRet = epoll_ctl (m_epfd, EPOLL_CTL_ADD, socket_fd, &event);

	if (nRet == -1)
	{
		return -1;
	}
	return 0;
#endif
}

//handle: sockid
//cb : socket callback fun
int CMyEpoll::MyDelSocketFdEvent(int socket_fd)
{
	for( int i = 0; i < _SOCKET_FD_MAX_; i++ )
	{
		if( CMyEpoll::m_socket_fd[i] == socket_fd )
		{
			CMyEpoll::m_socket_fd[i] = -1;
			CMyEpoll::m_cb[i] = NULL;
		}
	}
	return 0;
#ifdef WIN32

#else
	struct epoll_event event = {0};
	event.data.fd = socket_fd;
	event.events = EPOLLIN;
	int nRet = epoll_ctl (m_epfd, EPOLL_CTL_DEL, socket_fd, &event);

	if (nRet == -1)
	{
		return -1;
	}
	return 0;
#endif
}

MY_SOCKET_FD_CALLBACK CMyEpoll::MyGetSocketFdCallBack(int socket_fd)
{
	for( int i = 0; i < _SOCKET_FD_MAX_; i++ )
	{
		if( CMyEpoll::m_socket_fd[i] == socket_fd )
		{
			return CMyEpoll::m_cb[i];
		}
	}
	return NULL;
}

#define PROCESS_DATA_LEN	(4*1024)
static char data[PROCESS_DATA_LEN] = {0};
#ifdef WIN32

void CMyEpoll::RunThread( void )
{
	fd_set         fdread;
	fd_set         fdwrite;
	struct timeval tv = {0,20};
	//while(1)
		{
			if(CMyEpoll::m_exitflag )
				return ;
			
			FD_ZERO(&fdread);
			FD_ZERO(&fdwrite);

			for( int i = 0; i < _SOCKET_FD_MAX_; i++ )
			{
				if(CMyEpoll::m_socket_fd[i] != -1)
					{
						FD_SET(CMyEpoll::m_socket_fd[i], &fdread);
						FD_SET(CMyEpoll::m_socket_fd[i], &fdwrite);
					}
			}
				
			switch(select(0, &fdread, &fdwrite, NULL, &tv))
				{
					case 0:
						break;

					default:
					
						for( int i = 0; i < _SOCKET_FD_MAX_; i++ )
							{
								if(CMyEpoll::m_socket_fd[i] != -1)
									{
										if(FD_ISSET(CMyEpoll::m_socket_fd[i],&fdread))
											{
												char data[PROCESS_DATA_LEN] = {0};
												int count = recv(CMyEpoll::m_socket_fd[i], (char*)data, PROCESS_DATA_LEN, 0);
												if(CMyEpoll::m_cb[i] && count > 0)
													CMyEpoll::m_cb[i]( EVENT_READ, data, count );
											}
										if(!CMyEpoll::socketConnect[i] && FD_ISSET(CMyEpoll::m_socket_fd[i],&fdwrite))
											{
												CMyEpoll::socketConnect[i] = true;
												if(CMyEpoll::m_cb[i])
													CMyEpoll::m_cb[i]( EVENT_CONNECTED, NULL, 0 );
											}
									}
							}
						
						break;
				}
		}
	return ;
}
#else

void CMyEpoll::RunThread( void )
{
	int count = 0;
	int socket_fd;
	int eventnum = 0;
	int loop = 0;
	struct epoll_event allEvents[EVENTMAX] = {0};
	MY_SOCKET_FD_CALLBACK pfun = NULL;
	CMyEpoll *pmyepoll = (CMyEpoll *)this;
	//主循环
	//while(1)
	{
		if( CMyEpoll::m_exitflag )
		{
			//pthread_exit((void*)& "exit MyRun" );
			return ;
		}
		
		eventnum = 0;
		loop = 0;
		memset( allEvents, 0, sizeof(allEvents) );
		//等待事件
		eventnum = epoll_wait (pmyepoll->m_epfd, allEvents, EVENTMAX, 0 );
		for( loop = 0; loop < eventnum; loop++ )
		{
			socket_fd = allEvents[loop].data.fd;
			pfun = pmyepoll->MyGetSocketFdCallBack( socket_fd );
			//处理连接事件
			//连接成功
			if( allEvents[loop].events == EPOLLOUT )
			{
				struct epoll_event event = {0};
				event.data.fd = socket_fd;
				event.events = (EPOLLIN);
				epoll_ctl (pmyepoll->m_epfd, EPOLL_CTL_MOD, socket_fd, &event);
				if( pfun )
				{
					
					pfun( EVENT_CONNECTED, NULL, 0 );
					continue;
				}
			}
			//连接失败
			if( allEvents[loop].events == (EPOLLIN | EPOLLERR | EPOLLHUP) )
			{
				if( pfun )
				{
					pfun( EVENT_CONNECT_ERROR, NULL, 0 );
					pmyepoll->MyDelSocketFdEvent( socket_fd );
					continue;
				}
			}
			//发生错误
			if ( (allEvents[loop].events & EPOLLERR) || (allEvents[loop].events & EPOLLHUP) )
			{
				if( pfun )
				{
					pfun( EVENT_ERROR, NULL, 0 );
					pmyepoll->MyDelSocketFdEvent( socket_fd );
					continue;
				}
			}
			//循环接收数据
			if( allEvents[loop].events & EPOLLIN )
			{
				while( 1 )
				{
					count = recv( socket_fd, data, PROCESS_DATA_LEN, 0 );
					if( count < 0 )
					{
						if( errno != EAGAIN )
						{
							//通知应用
							if( pfun )
							{
								pfun( EVENT_ERROR, NULL, 0 );
							}
							pmyepoll->MyDelSocketFdEvent( socket_fd );
						}
						break;
					}
					else if( count == 0 )
					{
						//通知应用
						if( pfun )
						{
							pfun( EVENT_READ_ERROR, NULL, 0 );
						}
						pmyepoll->MyDelSocketFdEvent( socket_fd );
						break;
					}
					else
					{
						if( pfun )
						{
							pfun( EVENT_READ, data, count );
						}
						if( count < PROCESS_DATA_LEN )
						{
							break;
						}
					}
				}
			}
		}
	}
	return ;
}
#endif



你可能感兴趣的:(cocos2dx)