linux socket的select函数例子
在Linux系统中,`select`函数是用于网络编程中处理多路I/O复用的关键机制之一,它允许程序同时监控多个文件描述符(如网络套接字)的状态变化,而无需实际读取或写入数据。`select`函数在处理高并发连接请求时尤其有用,因为它可以高效地检测哪些套接字已经准备好进行读或写操作,从而避免了不必要的系统调用。 ### `select`函数详解 `select`函数的基本原型为: ```c #include <sys/select.h> int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); ``` 其中: - `nfds`:最高文件描述符加一。例如,如果最高文件描述符为10,则`nfds`应设置为11。 - `readfds`:一个`fd_set`类型的指针,用于指定待检测可读状态的文件描述符集合。 - `writefds`:一个`fd_set`类型的指针,用于指定待检测可写状态的文件描述符集合。 - `exceptfds`:一个`fd_set`类型的指针,用于指定待检测异常状态的文件描述符集合。 - `timeout`:一个`struct timeval`类型的指针,用于指定`select`调用的超时时间,如果设置为NULL,则`select`会阻塞直到有文件描述符发生变化。 ### 示例代码解析 在提供的示例代码中,我们看到了如何使用`select`函数来管理一个监听套接字和多个客户端连接。以下是对关键部分的详细解释: #### 初始化监听套接字 创建一个TCP套接字并将其绑定到特定端口上: ```c int sock_fd = socket(AF_INET, SOCK_STREAM, 0); ``` 然后设置套接字选项,以便在同一地址上重用端口: ```c int yes = 1; setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); ``` 接下来,将套接字绑定到本地地址和端口: ```c server_addr.sin_family = AF_INET; server_addr.sin_port = htons(MYPORT); server_addr.sin_addr.s_addr = INADDR_ANY; ``` 将套接字设置为监听模式,准备接受连接: ```c listen(sock_fd, BACKLOG); ``` #### 处理连接与`select`调用 在无限循环中,`select`被用来监控监听套接字和已连接的客户端套接字: ```c while (1) { FD_ZERO(&fdsr); FD_SET(sock_fd, &fdsr); // 设置超时时间为30秒 tv.tv_sec = 30; tv.tv_usec = 0; for (i = 0; i < BACKLOG; i++) { if (fd_A[i] != 0) { FD_SET(fd_A[i], &fdsr); } } ret = select(maxsock + 1, &fdsr, NULL, NULL, &tv); } ``` 在`select`调用返回后,程序检查是否有新的连接请求,或者已连接的客户端是否有数据可读或需要发送数据。通过这种方式,程序能够有效地管理多个并发连接,而不必为每个连接创建单独的线程或进程。 ### 总结 通过使用`select`函数,Linux下的网络服务器可以高效地处理大量并发连接,而不会消耗过多的系统资源。`select`的灵活性和效率使其成为网络编程中不可或缺的一部分,特别是在需要同时监控多个网络连接的场景下。然而,对于更高的并发量和更复杂的网络应用,现代系统往往倾向于使用更先进的I/O复用机制,如`epoll`,以获得更好的性能和扩展性。
使用select函数可以以非阻塞的方式和多个socket通信。程序只是演示select函数的使用,功能非常简单,即使某个连接关闭以后也不会修改当前连接数,连接数达到最大值后会终止程序。
1. 程序使用了一个数组fd_A,通信开始后把需要通信的多个socket描述符都放入此数组。
2. 首先生成一个叫sock_fd的socket描述符,用于监听端口。
3. 将sock_fd和数组fd_A中不为0的描述符放入select将检查的集合fdsr。
4. 处理fdsr中可以接收数据的连接。如果是sock_fd,表明有新连接加入,将新加入连接的socket描述符放置到fd_A。
#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 // the port users will be connecting to
#define BACKLOG 5 // how many pending connections queue will hold
#define BUF_SIZE 200
int fd_A[BACKLOG]; // accepted connection 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; // listen on sock_fd, new connection on new_fd
struct sockaddr_in server_addr; // server address information
struct sockaddr_in client_addr; // connector's address information
socklen_t sin_size;
int yes = 1;
char buf[BUF_SIZE];
int ret;
int i;
if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
perror("setsockopt");
剩余5页未读,继续阅读
- CNLucius2012-12-20从网上抄来的,没有自己的真知灼见!!!
- jhjh5552013-10-29一般般,那里都可以看到
- 粉丝: 18
- 资源: 392
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助