#include <stdio.h> // fprintf
#include <sys/event.h> // kqueue
#include <netdb.h> // addrinfo
#include <arpa/inet.h> // AF_INET
#include <sys/socket.h> // socket
#include <assert.h> // assert
#include <string.h> // bzero
#include <stdbool.h> // bool
#include <unistd.h> // close
const size_t BUF_SIZE = 1024;
static bool s_stop = true;
// 信号处理函数
static void handle_signal(int sig) {
s_stop = false;
}
int learn_kqueue(const char* ip, int32_t port) {
std::cout << "ip: " << ip << " port: " << port << std::endl;
signal(SIGTERM, handle_signal);
int sock = socket(PF_INET, SOCK_STREAM, 0);
assert(sock > 0);
// 强制使用TIME_WAIT状态的socket地址
int reuse = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
inet_pton(AF_INET, ip, &address.sin_addr); //主机序转网络序ip
address.sin_port = htons(port); //主机序转网络序
int ret = bind(sock, (struct sockaddr*)&address, sizeof(address));
assert(ret != -1);
ret = listen(sock, BACK_LOG);
assert(ret != -1);
//创建一个消息队列并返回kqueue描述符
int kq = kqueue();
assert(kq != -1);
struct kevent change_list[10]; //想要监控的事件
struct kevent event_list[10]; //用于kevent返回
char buf[BUF_SIZE];
// 监听sock的读事件
EV_SET(&change_list[0], sock, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
// 监听stdin的读事件
EV_SET(&change_list[1], fileno(stdin), EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
int nevents;
while (s_stop) {
printf("new loop...\n");
// 等待监听事件的发生
nevents = kevent(kq, change_list, 2, event_list, 2, NULL);
if (nevents < 0) {
printf("kevent error.\n"); // 监听出错
} else if (nevents > 0) {
printf("get events number: %d\n", nevents);
for (int i = 0; i < nevents; ++i) {
printf("loop index: %d\n", i);
struct kevent event = event_list[i]; //监听事件的event数据结构
int clientfd = (int) event.ident; // 监听描述符
// 表示该监听描述符出错
if (event.flags & EV_ERROR) {
close(clientfd);
printf("EV_ERROR: %s\n", strerror(event_list[i].data));
}
// 表示sock有新的连接
if (clientfd == sock) {
printf("new connection\n");
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int new_fd = accept(sock, (struct sockaddr *) &client_addr, &client_addr_len);
char remote[INET_ADDRSTRLEN];
printf("connected with ip: %s, port: %d\n",
inet_ntop(AF_INET, &client_addr.sin_addr, remote, INET_ADDRSTRLEN),
ntohs(client_addr.sin_port));
}
if (clientfd == fileno(stdin)) {
memset(buf, 0, BUF_SIZE);
fgets(buf, BUF_SIZE, stdin);
printf("data from stdin: %s\n", buf);
}
}
}
}
close(sock);
return 0;
}