//
// Created by chenshun on 2022/3/21.
//
#include <sys/socket.h>
#include <sys/event.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
const size_t PAGE = 1024 * 16;
const int kReadEvent = 1;
const int kWriteEvent = 2;
void updateEvent(int kqFd, int fd, int events) {
struct kevent ke;
if (events & kReadEvent) {
EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
kevent(kqFd, &ke, 1, NULL, 0, NULL);
}
if (events & kWriteEvent) {
EV_SET(&ke, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
kevent(kqFd, &ke, 1, NULL, 0, NULL);
}
}
void delEvent(int kqFd, int fd, int events) {
struct kevent ke;
if (events & kReadEvent) {
EV_SET(&ke, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
kevent(kqFd, &ke, 1, NULL, 0, NULL);
}
if (events & kWriteEvent) {
EV_SET(&ke, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
kevent(kqFd, &ke, 1, NULL, 0, NULL);
}
}
void handleAccept(int kq, int socket_fd) {
struct sockaddr_storage sa;
socklen_t salen = sizeof(sa);
int client = accept(socket_fd, (struct sockaddr *) &sa, &salen);
int flags = fcntl(client, F_GETFL, 0);
fcntl(client, F_SETFL, flags | O_NONBLOCK);
updateEvent(kq, client, kReadEvent);
}
void handleRead(int kq, int fd) {
char buf[PAGE];
size_t rr = read(fd, &buf, PAGE);
if (rr == 0) {
delEvent(kq, fd, kReadEvent | kWriteEvent);
close(fd);
return;
}
delEvent(kq, fd, kReadEvent);
if (rr == 6 && !strcmp("exit\r\n", buf)) {
write(fd, "good bye!\n", strlen("good bye!\n"));
close(fd);
return;
}
printf("receive bytes: %zu, i have receive your message: %s\n", rr, buf);
updateEvent(kq, fd, kWriteEvent);
}
void handleWrite(int kq, int fd) {
char *send = "i have receive your message, expect your next message\n";
write(fd, send, strlen(send));
delEvent(kq, fd, kWriteEvent);
updateEvent(kq, fd, kReadEvent);
}
void loop_once(int kq, int socket_fd, int waitms) {
struct timespec timeout;
timeout.tv_sec = waitms / 1000;
timeout.tv_nsec = (waitms % 1000) * 1000 * 1000;
struct kevent *event = malloc(sizeof(struct kevent *));
int retval = kevent(kq, NULL, 0, event, 20, &timeout);
if (retval > 0) {
printf("收到事件: %d 件\n", retval);
}
for (int i = 0; i < retval; i++) {
struct kevent ev = event[i];
uintptr_t fd = ev.ident;
if (ev.filter == EVFILT_READ) {
//处理可读时间
if (fd == socket_fd) {
handleAccept(kq, socket_fd);
} else {
handleRead(kq, (int) fd);
}
}
if (ev.filter == EVFILT_WRITE) {
//处理可写事件
handleWrite(kq, (int) fd);
}
}
free(event);
}
int main() {
int port = 19999;
int socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in *serv_addr = malloc(sizeof(struct sockaddr_in));
if (serv_addr == NULL) {
printf("分配内存失败");
exit(1);
}
serv_addr->sin_family = AF_INET;
serv_addr->sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr->sin_port = htons(port);
//
int on = 1;
setsockopt(socket_fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
int flags = fcntl(socket_fd, F_GETFL, 0);
fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK);
if (bind(socket_fd, (struct sockaddr *) serv_addr, sizeof(struct sockaddr)) < 0) {
printf("bind 失败!");
exit(1);
}
listen(socket_fd, 20);
printf("使用telnet 127.0.0.1 19999 来进行测试\n");
printf("输入exit来断开TCP链接\n");
int queue = kqueue();
//注册
updateEvent(queue, socket_fd, kReadEvent);
for (;;) {
loop_once(queue, socket_fd, 10000);
}
return 0;
}