通过epoll实现并发服务器
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <sys/socket.h>
int main() {
int server_socket, client_socket;
struct sockaddr_in server_addr, client_addr;
socklen_t client_addr_len;
char buffer[1024];
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
perror("Error creating socket");
return -1;
}
// 绑定
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);
if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
perror("Error binding");
close(server_socket);
return -1;
}
// 设置监听
if (listen(server_socket, 5) == -1) {
perror("Error listening");
close(server_socket);
return -1;
}
// 创建 epoll 对象
int epoll_fd = epoll_create1(0);
if (epoll_fd == -1) {
perror("Error creating epoll");
close(server_socket);
return -1;
}
struct epoll_event event, events[10];
event.events = EPOLLIN;
event.data.fd = server_socket;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_socket, &event) == -1) {
perror("Error adding server socket to epoll");
close(epoll_fd);
close(server_socket);
return -1;
}
while (1) {
int num_ready = epoll_wait(epoll_fd, events, 10, -1);
if (num_ready == -1) {
perror("Error in epoll_wait");
break;
}
for (int i = 0; i < num_ready; ++i) {
int fd = events[i].data.fd;
if (fd == server_socket) {
client_addr_len = sizeof(client_addr);
client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &client_addr_len);
if (client_socket == -1) {
perror("Error accepting connection");
continue;
}
printf("New connection from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// 设置非阻塞模式
fcntl(client_socket, F_SETFL, O_NONBLOCK);
event.events = EPOLLIN | EPOLLET;
event.data.fd = client_socket;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_socket, &event) == -1) {
perror("Error adding client socket to epoll");
close(client_socket);
continue;
}
} else {
ssize_t num_bytes = recv(fd, buffer, 1024, 0);
if (num_bytes == -1) {
perror("Error receiving data");
close(fd);
continue;
} else if (num_bytes == 0) {
// 客户端关闭连接
struct sockaddr_in client_address;
socklen_t addr_len = sizeof(client_address);
getpeername(fd, (struct sockaddr*)&client_address, &addr_len);
printf("Connection closed by %s:%d\n", inet_ntoa(client_address.sin_addr), ntohs(client_address.sin_port));
close(fd);
} else {
buffer[num_bytes] = '\0';
printf("Received data from %s:%d: %s\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buffer);
}
}
}
}
// 关闭监听套接字和epoll实例
close(epoll_fd);
close(server_socket);
return 0;
}