c语言select和accept,accept和select的区别

select:查看指定fd_set中socket状态,如果fd_set中有套接字准备就绪(触发(读、写或执行)),则会返回,返回值为触发的套接字个数

accept:经过创建套接字socket()绑定bind()以及listen()之后,将监听socket和客户端socket建立一个全新连接,并返回client的socket信息;

判断是否有客户端发起链接请求,   一般用select(),然后accept()。

应该先select,可以测一下超时。

如果先accept,select就没必要了。

还有select后,可以测一下资源,如果fd用完了,可以等归还;直接的accept,发生这事这个连接就丢了。

一般模型如下

初始化 (socket,bind,listen);

while(1)

{

设置监听读写文件描述符 (FD_SET*);

调用 select;

如果是倾听套接字就绪 , 说明一个新的连接请求建立

{

建立连接 (accept);

将accept返回的client fd加入到监听文件描述符中去 ;

}

否则说明是一个已经连接过的描述符

{

进行操作 (read 或者 write);

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一、select应用举例 下面的代码演示了如何使用select函数进行I/O多路复用,同时处理多个客户端的连接和消息收发: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define MAX_CLIENTS 10 #define BUFFER_SIZE 1024 int main(int argc, char *argv[]) { int server_socket, client_socket[MAX_CLIENTS], max_fd, activity, i, valread, sd; struct sockaddr_in server_addr, client_addr; fd_set readfds; char buffer[BUFFER_SIZE]; // 创建服务器socket if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket failed"); exit(EXIT_FAILURE); } // 设置服务器socket地址 memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(8888); // 绑定服务器socket到地址 if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { perror("bind failed"); exit(EXIT_FAILURE); } // 监听客户端连接 if (listen(server_socket, MAX_CLIENTS) == -1) { perror("listen failed"); exit(EXIT_FAILURE); } // 初始化客户端socket数组 for (i = 0; i < MAX_CLIENTS; i++) { client_socket[i] = 0; } // 输出服务器信息 printf("Server started on port %d\n", ntohs(server_addr.sin_port)); while (1) { // 清空文件描述符集合 FD_ZERO(&readfds); // 添加服务器socket到集合中 FD_SET(server_socket, &readfds); max_fd = server_socket; // 添加客户端socket到集合中 for (i = 0; i < MAX_CLIENTS; i++) { sd = client_socket[i]; // 如果socket有效,添加到集合中 if (sd > 0) { FD_SET(sd, &readfds); } // 更新最大文件描述符 if (sd > max_fd) { max_fd = sd; } } // 等待文件描述符上有活动事件 activity = select(max_fd + 1, &readfds, NULL, NULL, NULL); if ((activity < 0) && (errno != EINTR)) { perror("select failed"); exit(EXIT_FAILURE); } // 如果服务器socket有连接请求,处理连接 if (FD_ISSET(server_socket, &readfds)) { int new_socket, addrlen = sizeof(client_addr); if ((new_socket = accept(server_socket, (struct sockaddr *)&client_addr, (socklen_t *)&addrlen)) == -1) { perror("accept failed"); exit(EXIT_FAILURE); } // 输出新客户端信息 printf("New connection, socket fd is %d, ip is : %s, port : %d\n", new_socket, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); // 添加新客户端socket到数组中 for (i = 0; i < MAX_CLIENTS; i++) { if (client_socket[i] == 0) { client_socket[i] = new_socket; break; } } } // 处理客户端socket上的消息 for (i = 0; i < MAX_CLIENTS; i++) { sd = client_socket[i]; if (FD_ISSET(sd, &readfds)) { if ((valread = read(sd, buffer, BUFFER_SIZE)) == 0) { // 客户端关闭连接 getpeername(sd, (struct sockaddr *)&client_addr, (socklen_t *)&addrlen); printf("Client disconnected, ip is : %s, port : %d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); close(sd); client_socket[i] = 0; } else { // 处理客户端消息 buffer[valread] = '\0'; printf("Received message from client[%d], message is : %s\n", i, buffer); } } } } return 0; } ``` 二、epoll应用举例 下面的代码演示了如何使用epoll函数进行I/O多路复用,同时处理多个客户端的连接和消息收发: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/epoll.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define MAX_CLIENTS 10 #define BUFFER_SIZE 1024 int main(int argc, char *argv[]) { int server_socket, client_socket, epoll_fd, i, valread, sd; struct sockaddr_in server_addr, client_addr; struct epoll_event event, events[MAX_CLIENTS]; char buffer[BUFFER_SIZE]; // 创建服务器socket if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket failed"); exit(EXIT_FAILURE); } // 设置服务器socket地址 memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(8888); // 绑定服务器socket到地址 if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { perror("bind failed"); exit(EXIT_FAILURE); } // 监听客户端连接 if (listen(server_socket, MAX_CLIENTS) == -1) { perror("listen failed"); exit(EXIT_FAILURE); } // 创建epoll文件描述符 if ((epoll_fd = epoll_create(MAX_CLIENTS)) == -1) { perror("epoll_create failed"); exit(EXIT_FAILURE); } // 添加服务器socket到epoll事件中 event.events = EPOLLIN; event.data.fd = server_socket; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_socket, &event) == -1) { perror("epoll_ctl failed"); exit(EXIT_FAILURE); } // 输出服务器信息 printf("Server started on port %d\n", ntohs(server_addr.sin_port)); while (1) { // 等待epoll事件触发 int num_events = epoll_wait(epoll_fd, events, MAX_CLIENTS, -1); // 处理所有触发的事件 for (i = 0; i < num_events; i++) { // 如果是服务器socket有连接请求,处理连接 if (events[i].data.fd == server_socket) { int addrlen = sizeof(client_addr); if ((client_socket = accept(server_socket, (struct sockaddr *)&client_addr, (socklen_t *)&addrlen)) == -1) { perror("accept failed"); exit(EXIT_FAILURE); } // 输出新客户端信息 printf("New connection, socket fd is %d, ip is : %s, port : %d\n", client_socket, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); // 将客户端socket添加到epoll事件中 event.events = EPOLLIN; event.data.fd = client_socket; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_socket, &event) == -1) { perror("epoll_ctl failed"); exit(EXIT_FAILURE); } } else { // 处理客户端socket上的消息 sd = events[i].data.fd; if ((valread = read(sd, buffer, BUFFER_SIZE)) == 0) { // 客户端关闭连接 getpeername(sd, (struct sockaddr *)&client_addr, (socklen_t *)&addrlen); printf("Client disconnected, ip is : %s, port : %d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); close(sd); } else { // 处理客户端消息 buffer[valread] = '\0'; printf("Received message from client, message is : %s\n", buffer); } } } } return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值