linux select编程

来源:互联网 发布:巨人网络借壳a股上市 编辑:程序博客网 时间:2024/05/11 09:54

linux select编程

可以通过select写非阻塞io的程序,可以参考我的博客阻塞与非阻塞

函数介绍

select函数原型

 #include <sys/select.h>int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);参数:    第一个参数:int nfds是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1    第二个参数:fd_set *readfds 用来检查一组可读性的文件描述符。    第三个参数:fd_set *writefds 用来检查一组可写性的文件描述符。    第四个参数:fd_set *exceptfds 用来检查文件文件描述符是否异常    第五个参数:sreuct timeval *timeout是一个时间结构体,用来设置超时时间        timeout:最多等待时间,对阻塞操作则为NULL    时间体的结构:        struct timeval {        time_t         tv_sec;     /* seconds */          suseconds_t    tv_usec;    /* microseconds */        };返回值:    负值:select错误    正值:表示某些文件可读或可写    0:等待超时,没有可读写或错误的文件

select中常用的其他函数

void FD_CLR(int fd, fd_set *set);//用于在文件描述符集合中删除一个文件描述符。int  FD_ISSET(int fd, fd_set *set);//用于测试指定的文件描述符是否在该集合中。void FD_SET(int fd, fd_set *set);//用于在文件描述符集合中增加一个新的文件描述符void FD_ZERO(fd_set *set);//检查集合中指定的文件描述符是否可以读写

select的使用步骤

1 初始化,把当前的listenfd加入集合,初始化socketfd数组2 监听数据,接受到connfd把它加入集合3 循环处理文本,如果可读,读取长度,关闭sockfd4 循环处理文本,读取指定长度的数据,将长度和数据写入data5 往所有就绪的socketfd里面写入string

题外话,socket关闭后端口不可用

int   sockfd;   int   opt   =   1;   int   len   =   sizeof(opt);   sockfd   =   socket(AF_INET,   SOCK_STREAM,   0);   setsockopt(sockfd,   SOL_SOCKET,   SO_REUSEADDR,   &opt,   &len);

下面的
select编程的大致逻辑

1 设置 socket为非阻塞2 建立死循环-可以不用这么做3 初始化 fset4 将当前的set加入到里面5 循环遍历fset array---用于存储可用的soketfd的集合6 使用select监控文件句柄7 如果有fset,accpet接受socketfd,标识socketfd为可以读8 集中处理所有的fset array,处理读和写

实例

服务端的例子

#include <iostream>#include <arpa/inet.h>#include <unistd.h>#include <stdlib.h>#include <assert.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <unistd.h>#include <stdio.h>#include <netinet/in.h>#include <string.h>#include <sys/time.h>#include <sys/select.h>#include <sys/types.h>#include <fcntl.h>//using namespace std;#define BUFFER_SIZE 1024#define HEAD_LEN 4#define MAX_FD 1023#define BUF_LEN 1000void tsocket(int argc, const char * argv[]);int main(int argc, const char * argv[]) {    tsocket(argc,argv);    return 0;}void tsocket(int argc, const char * argv[]){    if(argc < 3){        exit(-1);    }    const char* ip = argv[1];    int port = atoi(argv[2]);    int backlog = atoi(argv[3]);    std::cout << "ip=" << ip << " port="<<port << " backlog=" << backlog  << std::endl;    //声明信息    char sockBuf[BUFFER_SIZE];    int socketfd[MAX_FD];    char data[BUFFER_SIZE+HEAD_LEN];    //接受数据    size_t ret;    int fd;    int check_ret;    fd = socket(PF_INET,SOCK_STREAM , 0);    assert(fd >= 0);    //端口重用    int   opt   =   1;       int   optLen   =   sizeof(opt);      setsockopt(fd, SOL_SOCKET,   SO_REUSEADDR,   &opt,   optLen);    struct sockaddr_in address;    bzero(&address,sizeof(address));    //转换成网络地址    address.sin_port = htons(port);    address.sin_family = AF_INET;    //地址转换    inet_pton(AF_INET, ip, &address.sin_addr);    //绑定ip和端口    check_ret = bind(fd,(struct sockaddr*)&address,sizeof(address));    assert(check_ret >= 0);    //非阻塞的socket    int cflags = fcntl(fd,F_GETFL,0);    fcntl(fd,F_SETFL, cflags|O_NONBLOCK);    //创建监听队列,用来存放待处理的客户连接    check_ret = listen(fd, backlog);    assert(check_ret >= 0);    struct sockaddr_in addressClient;    socklen_t clientLen = sizeof(addressClient);    //读的fd_set    fd_set  readset;     int  sockArray[MAX_FD];    int i,j,len,n;    int connfd;    for(i=0;i<MAX_FD;++i){        sockArray[i] = 0;    }    while(1){        //初始化 readset        FD_ZERO(&readset);        //把当前的socket加入监控        FD_SET(fd,&readset);        //如果出现可读,加入监控        for(i=0;i<MAX_FD;++i){            if(sockArray[i] == 1) FD_SET(i,&readset);        }        //select监视的文件句柄数,视进程中打开的文件数而定        //一般设为你要监视各文件        if (select(1024, &readset, NULL, NULL, NULL) < 0)        {            perror("select error");            exit(-1);        }        //将可读放入就绪里面        if(FD_ISSET(fd,&readset)){            connfd = accept(fd,NULL,NULL);            sockArray[connfd] = 1;            printf("client %d connected\n", connfd);        }        //集中处理可读        for(i=0;i<MAX_FD;++i){            if((sockArray[i] == 1) && FD_ISSET(i,&readset) ){                len = read(i,sockBuf,BUF_LEN);                if(len < 0){                    perror("read error");                    exit(-1);                }                //如果没有数据就等待                if(len == 0){                    close(i);                    sockArray[i] = 0;                    continue;                }                printf("client %d send %s\n", len, sockBuf);                //写入数据                write(i,sockBuf,len);            }        }    }    close(fd);}

客户端的例子

#include <iostream>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <signal.h>#include <unistd.h>#include <stdlib.h>#include <assert.h>#include <stdio.h>#include <string.h>#define BUF_LEN 1023void tserver(int argc, const char * argv[]);int main(int argc, const char * argv[]) {    tserver(argc,argv);    return 0;}void tserver(int argc, const char * argv[]){    std::cout << "t server" << std::endl;    if(argc < 3){        exit(-1);    }    const char* ip = argv[1];    int port = atoi(argv[2]);    int backlog = atoi(argv[3]);    std::cout << "ip=" << ip << " port="<<port << " backlog=" << backlog  << std::endl;    int fd;    int check_ret;    fd = socket(PF_INET,SOCK_STREAM , 0);    assert(fd >= 0);    struct sockaddr_in address;    bzero(&address,sizeof(address));    //转换成网络地址    address.sin_port = htons(port);    address.sin_family = AF_INET;    //地址转换    inet_pton(AF_INET, ip, &address.sin_addr);    check_ret = connect(fd, (struct sockaddr*) &address, sizeof(address));    assert(check_ret >= 0);    //发送数据    //const char* oob_data = "abc";    const char* normal_data = "my boy!";    send(fd, normal_data, strlen(normal_data), 0);    printf("send data len=%lu,msg=%s\n",strlen(normal_data),normal_data);    //接受数据    int len;    char sockBuf[BUF_LEN];    memset(sockBuf, '\0', BUF_LEN);    len = recv(fd, sockBuf, BUF_LEN-1, 0);    printf("receive data len=%d,msg=%s\n",len,sockBuf);    close(fd);}

参考:

http://www.cnblogs.com/wenqiang/p/5508541.html
0 0