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

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); }


相关文章:
Linux中select函数学习及实例笔记
Linuxselect函数学习及实例笔记_计算机软件及应用_IT/计算机_专业资料。Linux ...03/06/1404449.html /*使用 select 函数可以以非阻塞的方式和多个 socket ...
select多socket写法
selectsocket写法_计算机软件及应用_IT/计算机_专业资料。该实例是一个Linux UDP 多线程 实例,通过select实现非阻塞式的 消息等待处理。发现...
windows编程中select函数的使用
socket select 函数的详细讲解原型 int select( int nfds, fd_set* readfds,...{...} } 二、linux c 中 select(I/O 多工机制) 表头文件 #i nclude<...
Socket函数说明
第六章 6.1 库函数综述 6.1.1 accept() * bind() closesocket() * ...其中 select()函数在必要时可能 阻塞。 只使用了上述函数的 Berkeley Sockets ...
linux中select函数的使用
linuxselect函数的使用linuxselect函数的使用隐藏>> linuxselect 函数的使用 SelectSocket 编程中还是比较重要的,可是对于初学 Socket 的人来说都不 太...
套接字socket函数详解
套接字socket函数详解_计算机软件及应用_IT/计算机_专业资料。套接字socket函数...); 六、输入/输出多路复用---select() 用来检测一个或多个套接字的状态。 ...
select使用手册
The presence of out-of-band data shall be checked if the socket option ...关于select函数 2页 免费 select实例 18页 免费 套接字select模式 5页 免费 ...
socket函数手册
linux_Socket_函数集 25页 1下载券s​o​c​...器应用程序都用 send 函数来向 TCP 连接的另一端...同时使用 select 检测也是可写的, 但是过几秒钟之后...
windows和linux套接字中的select机制浅析
windows和linux套接字中的select机制浅析_计算机软件及应用_IT/计算机_专业资料。...(SOCKET_ERROR) , 表示有错误发生, 可以使用 WSAGetLastError ()函数来得到错误...
socket_recv函数使用心得
socket通讯关于recv函数的使用心得 recv 的超时总结说明:针对 recv 返回值,阻塞...三 多路复用 select( ) 四 测试实验(linux 下测试) 1、 Client 端与 server...
更多相关标签:
socket中select用法 | linux socket select | linux select函数详解 | linux select 详解 | linux socket详解 | linux select用法 | linux flock用法详解 | linux函数用法详解 |