用C语言实现一个非阻塞的服务器监听程序
时间: 2024-09-09 10:14:28 浏览: 81
在C语言中,要实现一个非阻塞的服务器监听程序,通常会利用`select()`、`epoll()`、或`poll()`等高级IO多路复用函数,这些系统调用可以在多个套接字上同时等待事件发生,而不会被阻塞。这里以`epoll`为例,因为它在Linux平台上性能较好。
以下是一个简单的使用`epoll`的非阻塞服务器监听示例:
```c
#include <stdio.h>
#include <sys/epoll.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define MAX_EVENTS 10
#define PORT 8080
struct event {
int epoll_fd;
int socket_fd;
struct sockaddr_in client_addr;
};
int main() {
int server_sock, max_events = MAX_EVENTS;
struct epoll_event events[MAX_EVENTS];
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
int epoll_fd;
// 创建监听套接字
server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (server_sock == -1) {
perror("socket failed");
return -1;
}
// 绑定地址和设置为非阻塞模式
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
perror("bind failed");
close(server_sock);
return -1;
}
setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &1, sizeof(int));
fcntl(server_sock, F_SETFL, O_NONBLOCK);
// 初始化epoll
epoll_fd = epoll_create1(0);
if (epoll_fd == -1) {
perror("epoll_create1 failed");
close(server_sock);
return -1;
}
// 将监听套接字加入epoll
events.events = EPOLLIN | EPOLLET;
events.data.fd = server_sock;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_sock, &events) == -1) {
perror("epoll_ctl add failed");
close(epoll_fd);
close(server_sock);
return -1;
}
printf("Server listening on port %d...\n", PORT);
while (true) {
// epoll_wait等待事件发生
int num_events = epoll_wait(epoll_fd, events, max_events, -1);
if (num_events <= 0) {
perror("epoll_wait error");
continue;
}
for (int i = 0; i < num_events; i++) {
if (events[i].data.fd == server_sock) { // 新连接到来
accept(server_sock, (struct sockaddr*)&client_addr, &client_len);
// 创建新的事件描述符并添加到epoll
struct event *new_event = realloc(events, sizeof(struct event) * (num_events + 1));
if (!new_event) {
perror("realloc failed");
continue;
}
new_event[num_events].events = EPOLLIN | EPOLLET;
new_event[num_events].data.fd = accept(server_sock, NULL, NULL);
new_event[num_events].data.ptr = NULL;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_event[num_events].data.fd, &new_event[num_events]) == -1) {
perror("epoll_ctl add failed");
close(new_event[num_events].data.fd);
} else {
events = new_event;
num_events++;
}
} else { // 处理已连接客户端的请求
char buffer[1024] = {0};
read(events[i].data.fd, buffer, sizeof(buffer));
// 这里处理客户端数据逻辑
printf("Received message from client: %s\n", buffer);
write(events[i].data.fd, "Hello, Client!", strlen("Hello, Client!"));
close(events[i].data.fd); // 关闭连接
}
}
}
free(events);
close(epoll_fd);
close(server_sock);
return 0;
}
阅读全文