您的位置:首页 > 其它

IO模型(三)select --选择机制

2008-08-26 17:28 316 查看
因为这个模型是后来才使用的,差一点就忘记了....这个模型是从UNIX里来的,是比较早的一种模型。上次总结的WSAEventSelect模型是微软将其进行改进后的版本。来看一下这个函数声明:

int select(
intnfds, //忽略
fd_set FAR*readfds, //读操作
fd_set FAR*writefds, //写操作
fd_set FAR*exceptfds, //错误
const struct timeval FAR*timeout //等待的最大时间
);

另外需要看一看几个操作函数:fd_set ,FD_SET,FD_ZERO,FD_ISSET

1.fd_set:是一个结构体:

typedef struct fd_set {
u_int fd_count; //记录个数
SOCKET fd_array[FD_SETSIZE]; //套接字数组
} fd_set;

2.FD_SET:是宏操作看一下整的代码:

#define FD_SET(fd, set) do { /
u_int __i; /
for (__i = 0; __i < ((fd_set FAR *)(set))->fd_count; __i++) { /
if (((fd_set FAR *)(set))->fd_array[__i] == (fd)) { /
break; /
} /
} /
if (__i == ((fd_set FAR *)(set))->fd_count) { /
if (((fd_set FAR *)(set))->fd_count < FD_SETSIZE) { /
((fd_set FAR *)(set))->fd_array[__i] = (fd); /
((fd_set FAR *)(set))->fd_count++; /
} /
} /
} while(0)

这是Winsock2头文件里的定义,如果没有看过MFC仿真,看到这样的代码一定很头痛,函数操作还可以写成这样...

其实它完成的功能就是将fd加载到记录set里。

3.#define FD_ZERO(set) (((fd_set FAR *)(set))->fd_count=0)

将记录set清零

4.#define FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)(fd), (fd_set FAR *)(set))

检测fd是否在记录set里

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

好了现在开始例子:

//前三步省略...

//1.Winsock2.2初始化

//2.建立套接字 ServerSock

//3.bind并listen

//4.将建立好的套接字加入记录数组里

fd_set fdSocket;

//清零

FD_ZERO(&fdSocket);

//将建立好的套接字加入到记录

FD_SET(ServerSock,&fdSocket);

//开启线程处理通信事件

HANDLE hThread = (HANDLE)_beginthreadex(0,0,ThreadProc,this,0,0);

//5.在线程里建立select模型

CSelectModelDlg* pDlg = (CSelectModelDlg*)pParam;//得到当前对话框的指针
SOCKADDR_IN addrClient;
int nLen = sizeof(SOCKADDR);
while(1)
{
//保存fdSocket

fd_set fdReadSocket = pDlg->fdSocket;

//建立select模型,由于只关心FD_READ则只需处理第二个参数即可
int nEvent = select(0,&fdReadSocket,NULL,NULL,NULL);
if (nEvent > 0)
{

//当有事件到来时,遍历记录集
for (int i = 0; i < pDlg->fdSocket.fd_count; i++)
{

//判断是否在记录集里

if (FD_ISSET(pDlg->fdSocket.fd_array[i],(SOCKADDR*)&fdReadSocket))
{

//如果是Server端的套接字,则处理accept
if (pDlg->ServerSocket == pDlg->fdSocket.fd_array[i])
{
if (pDlg->fdSocket.fd_count < FD_SETSIZE)
{
pDlg->ClientSocket = accept(pDlg->ServerSocket,(SOCKADDR*)&addrClient,&nLen);
char* ip = inet_ntoa(addrClient.sin_addr);
int nPort = ntohs(addrClient.sin_port);

//将返回的套接字加入到记录集里
FD_SET(pDlg->ClientSocket,&(pDlg->fdSocket)); //把ClientSocket加入到fdSocket
}
}
else
{

//如果不是Server端的套接字,则处理接收信息
pDlg->ClientSocket = pDlg->fdSocket.fd_array[i];
TCHAR szBuf[MAX_PATH] = {0};
int nRecv = recv(pDlg->fdSocket.fd_array[i],(char*)szBuf,MAX_PATH*sizeof(TCHAR),0);
if (nRecv >= 0)
{
szBuf[nRecv] = 0;
}
pDlg->SetDlgItemText(IDC_ED_RECV,szBuf);
}
}
}
}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

无论代码实现还是逻辑方面我认为select比WSAEvenSelect实现起来要繁琐一些,建立模型后select需要遍历判断,检验等操作,所以看个从习惯选择了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: