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
- select(Linux 编程)
- linux串口编程 select
- linux select编程
- linux select编程示例
- linux 下 select 编程
- Linux 网络编程中的select
- Linux 网络编程中的select
- linux编程 select函数说明
- Linux 网络编程中的select
- Linux网络编程之select
- Linux串口编程select方式
- Linux编程之select用法
- LINUX select socket编程 TCP
- linux网络编程之select
- linux下select编程学习
- linux网络编程 select()函数
- linux服务器编程之select
- Linux编程之select 详解
- [CodeVS 2185] 最长公共上升子序列:DP
- Frame里打开IE10 IE11 showModalDialog大小调整
- 双重判断加锁的单例设计模式
- linux EHCI DRIVER之中断处理函数ehci_irq()分析(一)
- Android NV21数据保存成JPG格式到SD卡
- linux select编程
- spring profile 多环境配置管理
- Java 正则表达式
- java file类操作常用类的结构
- linux EHCI DRIVER之中断处理函数ehci_irq()分析(二)
- 魔术方法之简单实例
- window bat xcopy用法示例
- Android:使用HttpClient访问HTTP/HTTPS服务器
- An internal error occurred during: "Updating Maven Project".Unsupported IClasspathEntry kind=4问题解决备忘