监视UDP报文的一个类

127 阅读1分钟

目标是用winsock2完成对UDP报文的监视。
UDP报文属于一种无连接的报文传送机制,所以发送速度快,如果没有报文次序的要求,应该属于一种很好的网络通讯方式。
为了实现对UDP报文的监视,我开了一个线程,专门用于等待UDP报文的到达信息,其中采用winsock I/O模型中的select异步模型-WSAEventSelect。
该模型最主要的特点是在网络事件发生时会投递一个事件对象句柄。
其中初始化winsock,注册select模型的的方法如下:

代码:

	//建立一个网络事件发生时要投递的事件对象
	m_socketEvent=WSACreateEvent();
	//选择异步socket模型
	::WSAEventSelect(m_sock,m_socketEvent, FD_READ);		

实现监视守护线程

代码:

UINT CUdpProc::UDPListen( LPVOID pParam )
{
	CUdpProc* proc=(CUdpProc*)pParam;
	//投递的网络事件
	WSANETWORKEVENTS networkEvents;
	DWORD dCount=1;
	//给主线程预留的管理事件,以关闭本线程
	while(::WaitForSingleObject(proc->m_event.m_hObject,300)!=WAIT_OBJECT_0)
	{
		
		if(proc->m_socketEvent==WSA_INVALID_EVENT)
		{
			break;
		}
		//阻塞UDP监听
		::WSAWaitForMultipleEvents(dCount,&(proc->m_socketEvent),FALSE,WSA_INFINITE,FALSE);
		//事件到达后的处理
		::WSAEnumNetworkEvents(proc->m_sock,proc->m_socketEvent,&networkEvents);
		if(networkEvents.lNetworkEvents & FD_READ) //如果是数据到达
		{
			if(networkEvents.iErrorCode[FD_READ_BIT]!=0)
			{
				TRACE("err code=%d/n",networkEvents.iErrorCode[FD_READ_BIT]);
			}
			else
				proc->DoMsgRead(); //处理数据
		}
		//重新设置投递的事件对象
		::WSAResetEvent(proc->m_socketEvent);
	}
	//告诉主线程,监听线程结束
	proc->m_eventListenClose.SetEvent();
	return 0L;
}		


由于子线程大部分时间处于阻塞状态,不会响应主线程发送的事件信号,所以关闭监视子线程的方法采取如下措施:

代码:

	//等待监听线程结束的事件信号
	while(::WaitForSingleObject(m_eventListenClose.m_hObject,50)!=WAIT_OBJECT_0)
	{
		//设置关闭线程事件
		m_event.PulseEvent();
		//设置激活socket事件
		::WSASetEvent(m_socketEvent);
		//设置取消监视事件
		::WSAEventSelect(m_sock,m_socketEvent,0);
	}
	//释放监视事件
	::WSACloseEvent(m_socketEvent);
	m_event.Unlock();
	m_eventListenClose.Unlock();
	if(m_sock!=INVALID_SOCKET)
	{
		::closesocket(m_sock);
		::WSACleanup();
	}

启动线程的方法很简单,

代码:

BOOL CUdpProc::StartListen()
{
	BOOL bResult=InitSock();
	AfxBeginThread(UDPListen,this);
	return bResult;

}