select详解、fcntl设置非阻塞、setsockopt()参数详解

int select (int maxfd + 1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval * timeout);

:select是一个计算机函数,位于头文件#include 。该函数用于监视文件描述符的变化情况——读写或是异常。

应用:

Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect、accept、recv或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回)。

可是使用Select就可以完成非阻塞(所谓非阻塞方式non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高)方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。

int select (int maxfd + 1,fd_set *readset,fd_set *writeset,
fd_set *exceptset,const struct timeval * timeout);

参数1:文件描述符的数量,因为文件描述符从0开始,所以此处的值为最大的文件描述符加1。
参数2(fd_set *readset):struct fd_set指针,可读文件描述符集合,用于检查可读性
参数3(fd_set *writeset):struct fd_set指针,可写文件描述符集合,用于检查可写性
参数4(fd_set *exceptset):struct fd_set指针,异常文件描述符集合,用于检查异常
参数5(struct timeval * timeout):select函数超时时间
一个指向timeval结构的指针,用于决定select等待I/o的最长时间


struct fd_set可以理解为一个集合,这个集合存放文件描述符,fd_set可通过系统宏函数来进行处理

操作fd_set的系统宏函数:
FD_ZERO(fd_set *fdset)         //清空fdset集合中所有的文件描述符 
FD_SET(int fd, fd_set *fdset)  //将文件描述符fd加入fdset集合中
FD_CLR(int fd, fd_set *fdset)   //将文件描述符fd从fdset集合中清除 
FD_ISSET(int fd, fdset *fdset)  //检查fdset集合中的fd是否可读写,>0表示可读写。 


struct timeval{
long tv_sec;      // 秒
long tv_usec;     // 微妙
}

select返回值:
如果有文件描述符的读写异常变化,select会返回一个大于0的值。
如果没有则在timeout的时间后select返回0,若发生错误返回负值。
可以传入NULL值,表示不关心任何文件的读/写/异常变化。

select()三个fd_set集合注意事项:

1.三个fd_set分别监视文件描述符的读写异常变化,当传入NULL值时,代表不关心当前装填类型的变化。如果三个指针都为NULL,我们就有了一个比sleep()函数更为精确的定时器(sleep()以毫秒为最小单位,这个以微秒为单位)。

select()参数5超时时间注意事项:

1.若将此参数置为NULL,就是将select置为阻塞状态,一直等到监视文件描述符集合中某个文件描述符发生变化为止

2.如将此参数设置为0秒0微秒,就变成一个非阻塞函数,不管文件描述符是否变化,都立即返回(有变化返回0,无变化返回正值)

3.若超时时间大于0,在超时时间到达之前检测到了就立即返回,超时时间到了也没检测到也返回。(注意:如果在超时时间到之前返回了,此时select的超时时间为超时时间减去检测所用的时间,如果我们想要保持超时时间不变,就必须在轮询中进行每次重新设置超时时间)

fcntl即F_SETFL,F_GETFL的使用,设置文件的flags(linux一切皆文件)

int fcntl(int fd, int cmd, ... /* arg */ );

1、获取文件的flags,即open函数的第二个参数:

       flags = fcntl(fd,F_GETFL,0);

2、设置文件的flags:

      fcntl(fd,F_SETFL,flags);

3、增加文件的某个flags,比如文件是阻塞的,想设置成非阻塞(可以使用这种方法将套接字设为非阻塞的):

       flags = fcntl(fd,F_GETFL,0);

       flags |= O_NONBLOCK;

      fcntl(fd,F_SETFL,flags);

4、取消文件的某个flags,比如文件是非阻塞的,想设置成为阻塞:

      flags = fcntl(fd,F_GETFL,0);

      flags &= ~O_NONBLOCK;

      fcntl(fd,F_SETFL,flags);

int getsockopt(int sockfd, int level, int optname,
                      void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname,
                      const void *optval, socklen_t optlen);
 

                SOL_SOCKET 
    -----------------------------------------------------
     参数optname            宏的作用         对应参数optaval的类型
     
    SO_BROADCAST     允许发送广播数据         int
    SO_DEBUG        允许调试            int 
    SO_DONTROUTE     不查找路由            int 
    SO_ERROR        获得套接字错误         int
    SO_KEEPALIVE      保持连接             int 
    SO_LINGER         延迟关闭连接          struct linger 
    SO_OOBINLINE        带外数据放入正常数据流  int 
    SO_RCVBUF       接收缓冲区大小       int
    SO_SNDBUF        发送缓冲区大小      int
    SO_RCVLOWAT      接收缓冲区下限       int
    SO_SNDLOWAT      发送缓冲区下限       int 
    SO_RCVTIMEO      接收超时             struct timeval
    SO_SNDTIMEO       发送超时              struct timeval 
    SO_REUSEADDR    允许重用本地地址和端口     int 
    SO_TYPE          获得套接字类型       int
    SO_BSDCOMPAT     与BSD系统兼容         int
    ======================================================
                        IPPROTO_IP
    ------------------------------------------------------
    IP_ADD_MEMBERSHIP    加入到组播组中               struct ip_mreq 
    IP_MULTICAST_IF      允许开启组播报文的接口       struct ip_mreq 

    IP_TOS       源于该套接字的每个IP包的Type-Of-Service(TOS 服务类型)字段。它被用来在网络上区分包的优先级>                                                        int

    IP_MULTICAST_TTL       设置多播组数据的TTL值        int

    --------------------------------------------------------

                        SOL_IP

     ----------------------------------------------------------

      IP_PKTINFO                 设置套接字传递pktinfo的辅助信息结构        int

      -------------------------------------------------------------

例子:

option = 1;
ret = setsockopt(g_cw_ac_ipv4_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof(option));                //设置套接字端口复用

option = 1;                       //设置套接字传递pktinfo的辅助信息结构
ret = setsockopt(g_cw_ac_ipv4_socket, SOL_IP, IP_PKTINFO, (void *)&option, sizeof(option));

 IP_PKTINFO:传递一条包含pktinfo结构(该结构提供一些来访包的相关信息)的IP_PKTINFO辅助信息。
    这个选项只对数据报类的套接字有效。
    struct in_pktinfo
    {
        unsigned int ipi_ifindex; /* 接口索引 */
        struct in_addr ipi_spec_dst; /* 路由目的地址 */
        struct in_addr ipi_addr; /* 头标识目的地址 */
    };

ipi_ifindex指的是接收包的接口的唯一索引。ipi_spec_dst指的是路由表记录中的目的地址,而ipi_addr 指的是包头中的目的地址。如果给 sendmsg传递了IP_PKTINFO,那么外
发的包会通过在ipi_ifindex中指定的接口发送出去,同时把ipi_spec_dst设置为目的地址。
    myip_setsockopt的代码实现中只是根据option_value是否为0,置或清inet->cmsg_flags的IP_CMSG_PKTINFO位。

你可能感兴趣的:(c语言,c++,开发语言)