樽中酒不空
分类: C/C++
2014-10-10 09:48:35
上文提到的UDPSocket,只是一个简单的socket封装,被动地调用。本文仿照MFC的CAsyncSocket方式做一个包装调用,不过事件响应采用select,不用MFC的窗口消息。
简单接口如下:
typedef void (*udp_data_cb)(int sockid, char *data, int len, int ip, int port, int timestamp, void* param);
class CUDPSession
{
CUDPSession();
virtual ~CUDPSession();
int Open(uint16_t usLocalPort, udp_data_cb cb, void* param);
int Close();
int Send(char* pBuff,uint32_t nLen,uint32_t ip,uint16_t port);
private:
udp_data_cb m_pCB;
void* m_pParam;
private:
static void* EventLoop(void* lpParameter );
void ProcessEvent();
void OnTimer();
int OnRecv(char* pBuff,uint32_t nLen, uint32_t ip,uint16_t port);
bool m_bEventLoopStarted;
CUDPSock m_udpIO;
pthread_t m_tid;
};
出于通用和简便上考虑,线程采用了pthread形式。在windwos下,可以参考:。
这个项目把windows的线程使用重新封装了一下,话说windows原生的线程函数实在是.....。
class实现只展示几个重点函数,其他在源码里。
int CUDPSession::Open(uint16_t usLocalPort, udp_data_cb cb, void* param)
{
m_pCB = cb;
m_pParam = param;
if (m_bEventLoopStarted)
return 0;
int iResult = m_udpIO.Open(usLocalPort);
if (iResult > 0)
{
pthread_create (&m_tid, NULL, EventLoop, this);
}
return iResult;
}
int CUDPSession::Close()
{
if (m_bEventLoopStarted)
{
m_bEventLoopStarted = false;
pthread_join(tid, NULL);
m_udpIO.Close();
}
return 0;
}
void* CUDPSession::EventLoop(void* lpParameter )
{
CUDPSession* pThis = (CUDPSession*)lpParameter;
pThis->ProcessEvent();
return 0;
}
void CUDPSession::ProcessEvent()
{
timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 50000; //50ms
fd_set fsRead;
char szBuffer[1500];
int iReceived = 0;
int iErrorCode = 0;
m_bEventLoopStarted = true;
bool bLastSend = false;
while (m_bEventLoopStarted)
{
FD_ZERO( &fsRead );
FD_SET(m_udpIO.m_handle, &fsRead);
int ret = select (1024, &fsRead, NULL, NULL, &timeout);
if (ret < 0)
{
//err
}
else if (ret == 0)
{
OnTimer();
}
else
{
if(FD_ISSET( m_udpIO.m_handle, &fsRead))
{
uint32_t ip;
uint16_t port;
iReceived = m_udpIO.Receive(szBuffer, 1500, ip, port);
if (iReceived > 0)
{
OnRecv(szBuffer, iReceived, ip, port);
}
else
{
//error
}
}
}
timeout.tv_sec = 0;
timeout.tv_usec = 50000;
}
}
void CUDPSession::OnTimer()
{
struct timeval cur;
gettimeofday(&cur, NULL);
int timestamp = (cur.tv_sec-start_time.tv_sec)*1000 + (cur.tv_usec - start_time.tv_usec)/1000;
//start_time是一个时间标志,在合适的位置初始化一下,gettimeofday(&start_time, NULL);定时时间到就重置。
}