一.服务端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <errno.h>
#define PORT 9190
#define BUFFER_SIZE 1024
#define EPOLL_SIZE 1024
// epoll文件描述符和epoll_wait()返回事件集合
struct event_loop {
int ep_fd;
struct epoll_event events[EPOLL_SIZE];
};
struct event_loop *ev_loop = NULL;
// 事件
struct event_item{
int sock_fd; // 事件的文件描述符
int (*callback)(int sock_fd, int event, void *arg); // 事件响应回调函数
char send_buffer[BUFFER_SIZE]; // 事件发送缓冲区
char receive_buffer[BUFFER_SIZE]; // 事件接收缓冲区
ssize_t str_len; // 接收缓冲区可读长度
};
// 错误处理
void error_handler(const char *message);
// 回调函数
int accept_callback(int sock_fd, int event, void *arg); // 坚挺套接字对应回调函数
int receive_callback(int sock_fd, int event, void *arg); // 可接收数据套接字回调函数
int send_callback(int sock_fd, int event, void *arg); // 可发送数据套接字回调函数
int main() {
int server_sock;
server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (server_sock == -1) {
error_handler("socket() error");
}
struct sockaddr_in server_address;
bzero(&server_address, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(PORT);
if (bind(server_sock, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) {
error_handler("bind() error");
}
if (listen(server_sock, 5) == -1) {
error_handler("listen() error");
}
// epoll_creat()
ev_loop = (struct event_loop *) malloc(sizeof(struct event_loop));
ev_loop->ep_fd = epoll_create(EPOLL_SIZE);
// 监听事件初始化
struct epoll_event event;
event.data.fd = server_sock;
event.events = EPOLLIN;
struct event_item *item = (struct event_item *)malloc(sizeof(struct event_item));
item->sock_fd = server_sock;
item->callback = accept_callback;
event.data.ptr = item;
// 向epoll()注册监听套接字事件
epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_ADD, server_sock, &event);
while (1) {
int ep_cnt = epoll_wait(ev_loop->ep_fd, ev_loop->events, EPOLL_SIZE, -1);
if (ep_cnt < 0) {
break;
}
for (int i = 0; i < ep_cnt; i++) {
if (ev_loop->events[i].events & EPOLLIN) {
// 可接受数据事件(监听套接字,可recv()数据套接字)
struct event_item *s = ev_loop->events[i].data.ptr;
s->callback(s->sock_fd, ev_loop->events[i].events, s);
}
if (ev_loop->events[i].events & EPOLLOUT) {
// 可发送数据事件
struct event_item *s = ev_loop->events[i].data.ptr;
s->callback(s->sock_fd, ev_loop->events[i].events, s);
}
}
}
return 0;
}
void error_handler(const char *message) {
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
int accept_callback(int sock_fd, int event, void *arg) {
// 接收客户端连接
int client_sock;
struct sockaddr_in client_address;
socklen_t client_address_size = sizeof(client_address);
client_sock = accept(sock_fd, (struct sockaddr *)&client_address, &client_address_size);
if (client_sock == -1) {
return -1;
} else {
char str[INET_ADDRSTRLEN];
printf("new connect from ip: %s port: %d\n", inet_ntop(AF_INET, &client_address.sin_addr.s_addr, str, INET_ADDRSTRLEN),
ntohs(client_address.sin_port));
}
// 注册事件
struct epoll_event ev;
ev.data.fd = client_sock;
ev.events = EPOLLIN;
struct event_item *ev_item = (struct event_item *) malloc(sizeof(struct event_item));
ev_item->sock_fd = client_sock;
ev_item->callback = receive_callback;
ev.data.ptr = ev_item;
epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_ADD, client_sock, &ev);
return 0;
}
int receive_callback(int sock_fd, int event, void *arg) {
struct event_item *s = (struct event_item *)arg;
s->str_len = recv(sock_fd, s->receive_buffer, BUFFER_SIZE, 0);
if (s->str_len < 0) {
epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_DEL, sock_fd, NULL);
close(sock_fd);
free(s);
return -1;
} else if (s->str_len == 0) {
epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_DEL, sock_fd, NULL);
close(sock_fd);
free(s);
return 0;
} else {
// 接收到数据,将监听状态变为可写
memcpy(s->send_buffer, s->receive_buffer, s->str_len);
struct epoll_event ev;
ev.events = EPOLLOUT;
ev.data.fd = sock_fd;
s->callback = send_callback;
ev.data.ptr = s;
epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_MOD, sock_fd, &ev);
bzero(s->receive_buffer, BUFFER_SIZE);
return s->str_len;
}
}
int send_callback(int sock_fd, int event, void *arg) {
// 发送完成,将事件变为可读
struct event_item *s = (struct event_item *)arg;
send(sock_fd, s->send_buffer, s->str_len, 0);
bzero(s->send_buffer, BUFFER_SIZE);
struct epoll_event ev;
ev.data.fd = sock_fd;
ev.events = EPOLLIN;
s->sock_fd = sock_fd;
s->callback = receive_callback;
ev.data.ptr = s;
epoll_ctl(ev_loop->ep_fd, EPOLL_CTL_MOD, sock_fd, &ev);
return 0;
}