当前位置:首页 >> 计算机软件及应用 >>

Linux socket select 函数用法详解


linux 的 socket 函数分为阻塞和非阻塞两种方式,比如 accept 函数,在阻塞模式下,它会一 直等待有客户连接。而在非阻塞情况下,会立刻返回。我们一般都希望程序能够运行在非阻 塞模式下。一种方法就是做一个死循环,不断去查询各个 socket 的状态,但是这样会浪费 大量的 cpu 时间。解决这个问题的一个方法就是使用 select 函数。使用 select 函数可以以非 阻塞的方式和多个 socket 通信。当有 socket 需要处理时,select 函数立刻返回,期间并不会 占用 cpu 时间。 例程分析: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define MYPORT 1234 #define BACKLOG 5 #define BUF_SIZE 200 int fd_A[BACKLOG]; int conn_amount; // 侦听端口 // 最大可连接客户端数量 // 连接的 FD 数组 // 当前连接的数量

void showclient() { int i; printf("client amount: %d\n", conn_amount); for (i = 0; i < BACKLOG; i++) { printf("[%d]:%d ", i, fd_A[i]); } printf("\n\n"); } int main(void) { int sock_fd, new_fd; struct sockaddr_in server_addr; struct sockaddr_in client_addr; socklen_t sin_size; int yes = 1; char buf[BUF_SIZE]; int ret; int i; // 侦听 sock_fd, 新连接 new_fd // server address information // connector's address information

//创建侦听 Socket if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("Create listening socket error!"); exit(1); } //配置侦听 Socket //SO_REUSEADDR BOOL 允许套接口和一个已在使用中的地址捆绑。 if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt error!"); exit(1); } server_addr.sin_family = AF_INET; // host byte order server_addr.sin_port = htons(MYPORT); // short, network byte order server_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero)); //绑定新创建的 Socket 到指定的 IP 和端口 if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { perror("bind error!"); exit(1); } //开始侦听,最大连接数为 BACKLOG if (listen(sock_fd, BACKLOG) == -1) { perror("listen error!"); exit(1); } printf("listen port %d\n", MYPORT); //监控文件描述符集合 fd_set fdsr; //监控文件描述符集合中最大的文件号 int maxsock; //Select 超时返回的时间。 struct tim tv; conn_amount = 0; sin_size = sizeof(client_addr); maxsock = sock_fd; while (1) { // 初始化文件描述符集合 initialize file descriptor set

FD_ZERO(&fdsr); // 把 Sock_fd 加入到文件描述符集合 FD_SET(sock_fd, &fdsr); // 超时设置 30 秒 tv.tv_sec = 30; tv.tv_usec = 0; // 把活动的 socket 的句柄加入到文件描述符集合中 for (i = 0; i < BACKLOG; i++) { if (fd_A[i] != 0) { FD_SET(fd_A[i], &fdsr); } } //Select 函数原型 //int select(nfds, readfds, writefds, exceptfds, timeout) //nfds: select 监视的文件句柄数,视进程中打开的文件数而定, 一般设为呢要监视各 文件中的 //最大文件号加一 //readfds:select 监视的可读文件句柄集合 //writefds:select 监视的可写文件句柄集合。 //exceptfds:select 监视的异常文件句柄集合。 //timeout:本次 select 的超时结束时间。 ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv); if (ret < 0) { perror("select error!"); break; } else if (ret == 0) { printf("timeout\n"); continue; } // 轮询各个文件描述符(socket) for (i = 0; i < conn_amount; i++) { //FD_ISSET(int fd, fdset *fdset):检查 fdset 联系的文件句柄 fd 是否可读 写, // >0 表示可读写。 if (FD_ISSET(fd_A[i], &fdsr)) { //接收数据 ret = recv(fd_A[i], buf, sizeof(buf), 0);

if (ret <= 0) //接收数据出错 { printf("client[%d] close\n", i); close(fd_A[i]); FD_CLR(fd_A[i], &fdsr); fd_A[i] = 0; } else { // 数据接收成功 //将接收数据的最后一位补 0 if (ret < BUF_SIZE) memset(&buf[ret], '\0', 1); printf("client[%d] send:%s\n", i, buf); } } } // 检查是否有新连接进来,如果有新连接进来,接收连接,生成新 socket, //并加入到监控文件描述符集合中。 if (FD_ISSET(sock_fd, &fdsr)) { //接受连接 new_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &sin_size); if (new_fd <= 0) { perror("accept socket error!"); continue; } // 将新的连接加入到监控文件描述符集合 if (conn_amount < BACKLOG) { fd_A[conn_amount++] = new_fd; printf("new connection client[%d] %s:%d\n", conn_amount,inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); if (new_fd > maxsock) maxsock = new_fd; } else { printf("max connections arrive, exit\n"); send(new_fd, "bye", 4, 0); close(new_fd); break; } }

showclient(); } // 关闭所有连接 for (i = 0; i < BACKLOG; i++) { if (fd_A[i] != 0) { close(fd_A[i]); } } exit(0); }


相关文章:
C++网络编程Select函数用法详解
C++网络编程Select函数用法详解 SocketSocket-Select 2008-09-14 11:31 Select ...{...} } 二、linux c 中 select(I/O 多工机制) 表头文件 #i nclude<...
linux—select详解(转载)
linuxselect函数的使用... 7页 免费 Linux重定向详解(编辑转... 10页 1下载...关于文件句柄,其实就是一个整数,通过 socket 函数的声明就明白了: int socket...
linux中select函数的使用
linuxselect函数的使用linuxselect函数的使用隐藏>> linuxselect 函数的使用 SelectSocket 编程中还是比较重要的,可是对于初学 Socket 的人来说都不 太...
select函数用法
select函数用法_计算机软件及应用_IT/计算机_专业资料。SelectSocket 编程中...linux/Linuxjs/20090308/159832.html) linux c 语言 select 函数用法 表头文件 ...
linux_socket_select_tcp_server_client
linux_socket_select_tcp_server_client_计算机软件及应用_IT/计算机_专业资料。...Linux网络编程超级详细笔... 43页 1下载券 Linuxselect函数使用详... 6页...
Socket编程中的select函数
Linuxselect函数使用详解... 6页 免费 Select函数实现原理分析 6页 1财富值...Socket编程中的select函数Socket编程中的select函数隐藏>> SelectSocket 编程...
linux select 语句
linux select 语句_信息与通信_工程科技_专业资料。结构介绍@的用法( linux select...socket 这个句柄里读取数据了, 因为 select 函数已经告诉我们这个句柄里有数据...
Linux后台网络编程中select
使用 select 完成非阻塞方式 IO (non-block,进程或线程执行此函数时不必非要等待...socket 描述符重新加入待检测集合中;select 适合处理一个 socket 描述符情况,...
Linux下select函数实现的聊天服务器
=-1; 97. int Clients::GetAllSocket(int* sockArray, int arrayLen ) { ...linuxselect函数 8页 1下载券 linuxselect函数的使用... 7页 免费 ©...
Linux串口select编程
Linux串口select编程_计算机软件及应用_IT/计算机_专业资料。Linux 下串口程序开发...Select函数格式(我所说的是 Unix 系统下的伯克利 socket 编程, 和 windows...
更多相关标签: