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需要遍历判断,检验等操作,所以看个从习惯选择了。
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需要遍历判断,检验等操作,所以看个从习惯选择了。
相关文章推荐
- IO模型(二)WSAEventSelect--事件选择机制
- TCP,UDP IO模型(一)WSAAsyncSelect 异步选择
- WinSock IO模型二: WSAAsyncSelect 消息机制
- (五十三)高并发服务器——多路IO转接机制Select模型
- 模型设计与实践---(五)事件选择(EventSelect iO)
- WinSock IO模型三: WSAEventSelect 事件机制
- Socket I/O模型之事件选择(WSAEventSelect)
- WinSock IO模型 -- WSAEventSelect模型事件触发条件说明
- select ---IO 模型
- 一、选择模型(select)
- 三、事件选择模型(WSAEventSelect)
- Winsock异步模式I/O模型WSAEventSelect的使用及FD_WRITE事件的触发机制
- 很幽默的讲解六种Socket IO模型 Delphi版本(自己Select查看,WM_SOCKET消息通知,WSAEventSelect自动收取,Overlapped I/O 事件通知模型,Overlapped I/O 完成例程模型,IOCP模型机器人)
- 同步异步阻塞非阻塞网络IO模型select/epoll
- IO模型(select, poll, epoll的区别和原理)
- linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO
- Linux中select IO复用机制
- Socket I/O模型之事件选择(WSAEventSelect)(转)
- io复用之select机制
- Socket I/O模型之事件选择(WSAEventSelect)