select(),fd_set,FD_SET,FD_CLR,FD_ZERO,FD_ISSET的用法
2015-12-31 14:23
555 查看
本文大致记录一下我对socket编程中的select()方法,类型fd_set以及FD_SET、FD_ZERO、FD_CLR、FD_ISSET这些宏的用法的了解,
有不当的地方,请指出。
1 select
在socket编程中,select的字面意思就是选择,也就是选择出那些可读或可写或出错的socket,其声明如下:
[cpp] view
plaincopy
int select(
__in int nfds,
__inout fd_set* readfds,
__inout fd_set* writefds,
__inout fd_set* exceptfds,
__in const struct timeval*
timeout
);
[cpp] view
plaincopy
int select(
__in int nfds,
__inout fd_set* readfds,
__inout fd_set* writefds,
__inout fd_set* exceptfds,
__in const struct timeval* timeout
);
在Winsock和Berkeley socket中,第一个参数的意义不一样,Winsock中第一个参数被忽略掉,传0即可,Berkeley中,第一个参数要比
所有加入fd_set集合中的socket的值大,一般传递最大的socket值再加1.
select()方法一般用于非阻塞socket中,用于查询socket的状态,如上所述,查询socket是否可读或写或者出错。
2 fd_set
fd_set是一种类型,表示文件描述符的集合,socket编程中,可以理解为socket的集合,这种类型在select()方法的中间三个参数
中被用到,这三个参数分别表示可读socket集合、可写socket集合和出错socket集合。
3 FD_SET(fd, set)
Winsock中,FD_SET是一个宏定义,等价的方法描述如下,可以看出,FD_SET这个宏的作用就是把socket添加到一个fd_set类型的集合中。
[cpp] view
plaincopy
void FdSet(int fd,
fd_set *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 (false);
}
[cpp] view
plaincopy
void FdSet(int fd, fd_set *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 (false);
}
4 FD_ZERO和FD_CLR
这两个宏分别表示将一个fd_set类型的集合清空以及从集合中删除某个socket。
5 FD_ISSET
判断某个socket是否在fd_set类型的集合中。Winsock中,这个宏的定义如下:
[cpp] view
plaincopy
#define FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)(fd), (fd_set
FAR *)(set))
[cpp] view
plaincopy
#define FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)(fd), (fd_set FAR *)(set))
那么,这几个类型及方法是如何关联使用的呢?关键在于select()方法。
在使用select方法前,可以先分别初始化几个fd_set类型变量,如下:
[cpp] view
plaincopy
fd_set readSet;
fd_set writeSet;
[cpp] view
plaincopy
fd_set readSet;
fd_set writeSet;
然后将所要查询的socket放入这些集合中:
[cpp] view
plaincopy
FD_ZERO(&readSet); //
先初始化
FD_ZERO(&writeSet);
FD_SET(m_socket, &readSet);
FD_SET(m_socket, &writeSet);
[cpp] view
plaincopy
FD_ZERO(&readSet); // 先初始化
FD_ZERO(&writeSet);
FD_SET(m_socket, &readSet);
FD_SET(m_socket, &writeSet);
这时候,m_socket这个socket已经同时存在于readSet和writeSet这两个集合中。
然后调用select()方法来查询readSet和writeSet中存储的所有socket的状态,在select()执行完成后,此方法会清除readSet中
不可读的socket以及writeSet中清除不可写的socket,接着就可以调用FD_ISSET来判断m_socket是否还在readSet和writeSet中,如果不在,
则表示m_socket当前不可读也不可写,如果都在,则表示可读可写。最后就可以根据FD_ISSET的结果来做相应的处理。
至于select()方法的timeout参数,是用来设置select的超时时间的。
为了保险起见,在FD_ISSET调用成功后,再做如下判断:
[cpp] view
plaincopy
int iRet
= 0;
int len
= sizeof(iRet);
if (getsockopt(m_sock,
SOL_SOCKET, SO_ERROR, (char*)&iRet,
&len) == SOCKET_ERROR)
{
有不当的地方,请指出。
1 select
在socket编程中,select的字面意思就是选择,也就是选择出那些可读或可写或出错的socket,其声明如下:
[cpp] view
plaincopy
int select(
__in int nfds,
__inout fd_set* readfds,
__inout fd_set* writefds,
__inout fd_set* exceptfds,
__in const struct timeval*
timeout
);
[cpp] view
plaincopy
int select(
__in int nfds,
__inout fd_set* readfds,
__inout fd_set* writefds,
__inout fd_set* exceptfds,
__in const struct timeval* timeout
);
在Winsock和Berkeley socket中,第一个参数的意义不一样,Winsock中第一个参数被忽略掉,传0即可,Berkeley中,第一个参数要比
所有加入fd_set集合中的socket的值大,一般传递最大的socket值再加1.
select()方法一般用于非阻塞socket中,用于查询socket的状态,如上所述,查询socket是否可读或写或者出错。
2 fd_set
fd_set是一种类型,表示文件描述符的集合,socket编程中,可以理解为socket的集合,这种类型在select()方法的中间三个参数
中被用到,这三个参数分别表示可读socket集合、可写socket集合和出错socket集合。
3 FD_SET(fd, set)
Winsock中,FD_SET是一个宏定义,等价的方法描述如下,可以看出,FD_SET这个宏的作用就是把socket添加到一个fd_set类型的集合中。
[cpp] view
plaincopy
void FdSet(int fd,
fd_set *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 (false);
}
[cpp] view
plaincopy
void FdSet(int fd, fd_set *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 (false);
}
4 FD_ZERO和FD_CLR
这两个宏分别表示将一个fd_set类型的集合清空以及从集合中删除某个socket。
5 FD_ISSET
判断某个socket是否在fd_set类型的集合中。Winsock中,这个宏的定义如下:
[cpp] view
plaincopy
#define FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)(fd), (fd_set
FAR *)(set))
[cpp] view
plaincopy
#define FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)(fd), (fd_set FAR *)(set))
那么,这几个类型及方法是如何关联使用的呢?关键在于select()方法。
在使用select方法前,可以先分别初始化几个fd_set类型变量,如下:
[cpp] view
plaincopy
fd_set readSet;
fd_set writeSet;
[cpp] view
plaincopy
fd_set readSet;
fd_set writeSet;
然后将所要查询的socket放入这些集合中:
[cpp] view
plaincopy
FD_ZERO(&readSet); //
先初始化
FD_ZERO(&writeSet);
FD_SET(m_socket, &readSet);
FD_SET(m_socket, &writeSet);
[cpp] view
plaincopy
FD_ZERO(&readSet); // 先初始化
FD_ZERO(&writeSet);
FD_SET(m_socket, &readSet);
FD_SET(m_socket, &writeSet);
这时候,m_socket这个socket已经同时存在于readSet和writeSet这两个集合中。
然后调用select()方法来查询readSet和writeSet中存储的所有socket的状态,在select()执行完成后,此方法会清除readSet中
不可读的socket以及writeSet中清除不可写的socket,接着就可以调用FD_ISSET来判断m_socket是否还在readSet和writeSet中,如果不在,
则表示m_socket当前不可读也不可写,如果都在,则表示可读可写。最后就可以根据FD_ISSET的结果来做相应的处理。
至于select()方法的timeout参数,是用来设置select的超时时间的。
为了保险起见,在FD_ISSET调用成功后,再做如下判断:
[cpp] view
plaincopy
int iRet
= 0;
int len
= sizeof(iRet);
if (getsockopt(m_sock,
SOL_SOCKET, SO_ERROR, (char*)&iRet,
&len) == SOCKET_ERROR)
{
相关文章推荐
- Visual Studio2015设置Android SDK路径
- Android M版本设置数据主卡的流程
- Java Swing 字体居中显示
- 【mongo】启动mongo
- php的数组与数据结构
- python实现爬虫统计学校BBS男女比例(一)
- 基本git命令
- C# 写XML格式的字符串 (是否保存到硬盘)
- 分享几种比较简单实用的JavaScript tabel切换
- You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version
- 14.为主题配置图片性能
- html5元素拖曳的小小实践
- OpenCV使用笔记
- js页面跳转整理
- Flex 布局教程:语法篇
- Android Studio下JNI编程(引入外部或AS自行编译so文件)
- Oracle启动时提示map size mismatch; abort
- eclipse常用快捷键大全
- VMwareWorkstation10安装OS_X_Mavericks10.9.2图文详细教程
- 网易云音乐歌单的推荐算法