事件选择:Winsock提供了另一个有用的异步I/O模型

来源:互联网 发布:大数据招聘 编辑:程序博客网 时间:2024/05/21 06:11
/********************************************************************
created: 2016/09/24
created: 24:9:2016   14:36
filename: D:\code\SocketClassify\SocketClassify\TCPServ_SelectEvent.h
file path: D:\code\SocketClassify\SocketClassify
file base: TCPServ_SelectEvent
file ext: h
author: singebogo-singebogo@163.com


purpose: 事件选择:Winsock提供了另一个有用的异步I/O模型
Function: WSAAsyncSelect模型类似的是,它也允许应用程序在一个或多个套接字上,接收以事件为基 础的网络事件通知。
Function: 对于表1总结的、由WSAAsyncSelect模型采用的网络事件来说,它们均可原封不动地移植到新模型。
Note: 在用新模型开发的应用程序 中,也能接收和处理所有那些事件。
Note:
*********************************************************************/
#pragma once


#ifndef __I_TCPSERV_SELECTEVENT
#define __T_TCPSERV_SELECTEVENT


/****************************头文件库*******************************/
#include "socket/UsrSocket.h"


#include<cstdio>
#include <iostream>
using namespace std;






/****************************宏定义*********************************/


#define  IPPORT 4000 // ip 端口
#define  MAXBACKLOG SOMAXCONN// 客户最大连接数






/****************************函数实现*******************************/
#ifdef __cplusplus
extern "C" {
#endif


//// 数据定义
int g_evn_itotalconn = 0;// 连接数量singre
SOCKET g_evn_clientsocketarry[MAXIMUM_WAIT_OBJECTS] = {0};// 套接字对象数组


WSAEVENT g_evn_clienteventarry[MAXIMUM_WAIT_OBJECTS] = {0};// 事件对象数组




//// 函数声明
void CreateTcpServ_SelectEventModel();// 套接字初始化,监听,绑定,accept 网络事件对象,client套接字对象创建
DWORD WINAPI WorkerThread_EventSel(LPVOID lpParam);//工作者线程  
void Cleanup(int index);//清掉 网络事件对象数组,套接字对象数组


//// 函数实现
// The WSAEventSelect function specifies an event object to be associated with the specified set of FD_XXX network events
// int WSAEventSelect(
// __in  SOCKET s,  A descriptor identifying the socket.
// __in  WSAEVENT hEventObject,  A handle identifying the event object to be associated with the specified set of FD_XXX network events.
// __in  long lNetworkEvents  A bitmask that specifies the combination of FD_XXX network events in which the application has interest.
// );
//  The return value is zero if the application's specification of the network events and the associated event object was successful. Otherwise, 
// the value SOCKET_ERROR is returned, and a specific error number can be retrieved by calling WSAGetLastError. 
//************************************
// Method:    CreateTcpServ_SelectEventModel
// FullName:  CreateTcpServ_SelectEventModel
// Access:    private 
// Returns:   void
// Qualifier:
// Note1:
// Note2:
//************************************
void CreateTcpServ_SelectEventModel()
{
CUsrSocket us_socket;


CUsrSocket::_STOCKET _socket_param;
_socket_param._af = AF_INET;
_socket_param._protocol = SOCK_STREAM;
_socket_param._type = 0;


CUsrSocket::_SOCKET_ADDR _socket_addrparam;
_socket_addrparam._b_addrany = true;
_socket_addrparam._i_port = IPPORT;
_socket_addrparam._str_ip = "";


DWORD dw_threadid;


// 初始化套接字
if(us_socket.InitWSAData(us_socket._wVersionRequested, us_socket._wsaData))
{
cout<<"InitWSAData successed!"<<endl;
}else{
cout<<"InitWSAData fauiled!"<<endl;
return;
}


// 创建套接字对象
us_socket._socket_no = us_socket.CreateSocket(_socket_param._af, _socket_param._protocol, _socket_param._type);


// 设置套接字地址
us_socket._socket_addr = us_socket.SetSocketAddr(_socket_addrparam._b_addrany , 
_socket_addrparam._str_ip, _socket_addrparam._i_port);


// bind
us_socket.SocketBind(us_socket._socket_no, us_socket._socket_addr);


// listen
us_socket.SocketListen(us_socket._socket_no, MAXBACKLOG);


// Create worker thread  
//创建线程   
CreateThread(NULL, 0, WorkerThread_EventSel, NULL, 0, &dw_threadid);  




while (1)
{
us_socket._socket_conn = us_socket.SocketAccept(us_socket._socket_no, us_socket._socket_client);
if (us_socket._socket_conn == INVALID_SOCKET)
continue;
else{
//这里client的SOCKADDR_IN  client 中可以取出IP  
cout<<"Accepted client:" <<inet_ntoa(us_socket._socket_client.sin_addr)<<ntohs(us_socket._socket_client.sin_port)<<endl;  
// Add socket to g_evn_clientsocketarry  
//把客户端套接字放入数组中  
g_evn_clientsocketarry[g_evn_itotalconn] = us_socket._socket_conn;  
g_evn_clienteventarry[g_evn_itotalconn] = WSACreateEvent();//创建一个事件对象并保存到数组  
//可以在这里加入对数组大小的判断,从而用多个数组来分组。一组可以达到64个。  
//*******************************************  
//主要函数 事件选择  
//分组的话应当也是在用几个事件对象才行   事件对象g_evn_clienteventarry在interest中如果含有事件FD_READ|FD_Close事件,进入工作线程
if(0 == WSAEventSelect(g_evn_clientsocketarry[g_evn_itotalconn],  \
g_evn_clienteventarry[g_evn_itotalconn],  \
FD_READ | FD_CLOSE))
{
cout<<"WSAEventSelect successed! "<<g_evn_clientsocketarry[g_evn_itotalconn]<<"--"<<g_evn_clienteventarry[g_evn_itotalconn]<<endl;
}
g_evn_itotalconn++;  


//-send-
char sendBuf[DEFAULT_BUFLEN];  
memset(sendBuf, 0 , DEFAULT_BUFLEN);
sprintf(sendBuf,"Welcome %s to here!",inet_ntoa(us_socket._socket_client.sin_addr));//inet_ntoa网络地址转换转点分十进制的字符串指针  
send(us_socket._socket_conn, sendBuf, strlen(sendBuf)+1,0);
}
}
us_socket.CleanWSAData();
return;
}


// The WSAWaitForMultipleEvents function returns when one or all of the specified event objects are in the signaled state,
// when the time-out interval expires, or when an I/O completion routine has executed.
// DWORD WSAWaitForMultipleEvents(
// __in  DWORD cEvents,  The number of event object handles in the array pointed to by lphEvents,
//  The maximum number of event object handles is WSA_MAXIMUM_WAIT_EVENTS. One or more events must be specified. 
// __in  const WSAEVENT *lphEvents, A pointer to an array of event object handles.
// __in  BOOL fWaitAll, A value that specifies the wait type. If TRUE, the function returns when the state of all objects in the lphEvents
//     array is signaled. If FALSE, the function returns when any of the event objects is signaled. 
// __in  DWORD dwTimeout, The time-out interval, in milliseconds.
// __in  BOOL fAlertable A value that specifies whether the thread is placed in an alertable wait state so the system can execute I/O completion routines.
// );
// The return value is zero if the operation was successful. Otherwise, the value SOCKET_ERROR is returned, and a specific error number can be 
// retrieved by calling WSAGetLastError. 
// int WSAEnumNetworkEvents(
// __in   SOCKET s,  A descriptor identifying the socket.
// __in   WSAEVENT hEventObject, An optional handle identifying an associated event object to be reset.
// __out  LPWSANETWORKEVENTS lpNetworkEvents  A pointer to a WSANETWORKEVENTS structure that is filled with a record of network events that occurred and any associated error codes.
// );



//************************************
// Method:    WorkerThread_EventSel
// FullName:  WorkerThread_EventSel
// Access:    private 
// Returns:   DWORD WINAPI
// Qualifier:
// Parameter: LPVOID lpParama
// Note1:
// Note2:
//************************************
DWORD WINAPI WorkerThread_EventSel(LPVOID lpParama)
{
int ret, index;


WSANETWORKEVENTS p_networkevents;


char szMessage[DEFAULT_BUFLEN];
memset(szMessage, 0, DEFAULT_BUFLEN);


while (true)
{
// 关键api函数
ret = WSAWaitForMultipleEvents(g_evn_itotalconn, g_evn_clienteventarry, FALSE, 1000, FALSE);


if (ret == WSA_WAIT_FAILED || ret == WSA_WAIT_TIMEOUT)
{
continue;
}


index = ret - WSA_WAIT_EVENT_0;// 取对应事件的发生项
cout<<"index :"<<index<<endl;


if(SOCKET_ERROR == WSAEnumNetworkEvents(g_evn_clientsocketarry[index], g_evn_clienteventarry[index], &p_networkevents))
{
cout<<"WSAEnumNetworkEvents Fauiled!"<<endl;
return 0;
}


if (p_networkevents.lNetworkEvents & FD_READ)// read 网络事件
{
memset(szMessage, 0 , DEFAULT_BUFLEN);
ret = recv(g_evn_clientsocketarry[index], szMessage, DEFAULT_BUFLEN, 0);//接收 
cout<<szMessage<<endl;
if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET))  
{  
Cleanup(index);//掉线\退出的错误则处理  
}  
else // 发送服务器信息给客户端
{  
szMessage[ret] = '\0';  
send(g_evn_clientsocketarry[index], szMessage, strlen(szMessage), 0);//返回客户端原信息  

}
if(p_networkevents.lNetworkEvents == FD_CLOSE)
{
Cleanup(index);
}
}
return 0;
}


//************************************
// Method:    Cleanup
// FullName:  Cleanup
// Access:    private 
// Returns:   void
// Qualifier: 
// Parameter: int p_index
// Note1: 对于关闭的套接字 关闭对应的套接字数组和网络事件对象数组值,g_evn_itotalconn连接总数对应变化
// Note2:
//************************************
void Cleanup(int p_index)
{
cout<<"socketno: "<<g_evn_clientsocketarry[p_index]<<"--- EventNo: "<<g_evn_clienteventarry[p_index]<<endl;

WSACloseEvent(g_evn_clienteventarry[p_index]);
closesocket(g_evn_clientsocketarry[p_index]);

if(p_index <= g_evn_itotalconn - 1){
if (p_index == g_evn_itotalconn - 1)
{
g_evn_clienteventarry[g_evn_itotalconn - 1] = 0;
g_evn_clientsocketarry[g_evn_itotalconn - 1] = 0;
}else{
g_evn_clienteventarry[p_index] = g_evn_clienteventarry[g_evn_itotalconn - 1];
g_evn_clientsocketarry[p_index] = g_evn_clientsocketarry[g_evn_itotalconn - 1];
}
}
g_evn_itotalconn --;
cout<<"total conn: "<<g_evn_itotalconn<<endl;
}


#ifdef __cplusplus
}
#endif
#endif

0 0
原创粉丝点击