1. //
    2. // Created by chenshun on 2022/3/21.
    3. //
    4. #include <sys/socket.h>
    5. #include <sys/event.h>
    6. #include <netinet/in.h>
    7. #include <arpa/inet.h>
    8. #include <fcntl.h>
    9. #include <unistd.h>
    10. #include <stdio.h>
    11. #include <string.h>
    12. #include <stdlib.h>
    13. const size_t PAGE = 1024 * 16;
    14. const int kReadEvent = 1;
    15. const int kWriteEvent = 2;
    16. void updateEvent(int kqFd, int fd, int events) {
    17. struct kevent ke;
    18. if (events & kReadEvent) {
    19. EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
    20. kevent(kqFd, &ke, 1, NULL, 0, NULL);
    21. }
    22. if (events & kWriteEvent) {
    23. EV_SET(&ke, fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
    24. kevent(kqFd, &ke, 1, NULL, 0, NULL);
    25. }
    26. }
    27. void delEvent(int kqFd, int fd, int events) {
    28. struct kevent ke;
    29. if (events & kReadEvent) {
    30. EV_SET(&ke, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
    31. kevent(kqFd, &ke, 1, NULL, 0, NULL);
    32. }
    33. if (events & kWriteEvent) {
    34. EV_SET(&ke, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
    35. kevent(kqFd, &ke, 1, NULL, 0, NULL);
    36. }
    37. }
    38. void handleAccept(int kq, int socket_fd) {
    39. struct sockaddr_storage sa;
    40. socklen_t salen = sizeof(sa);
    41. int client = accept(socket_fd, (struct sockaddr *) &sa, &salen);
    42. int flags = fcntl(client, F_GETFL, 0);
    43. fcntl(client, F_SETFL, flags | O_NONBLOCK);
    44. updateEvent(kq, client, kReadEvent);
    45. }
    46. void handleRead(int kq, int fd) {
    47. char buf[PAGE];
    48. size_t rr = read(fd, &buf, PAGE);
    49. if (rr == 0) {
    50. delEvent(kq, fd, kReadEvent | kWriteEvent);
    51. close(fd);
    52. return;
    53. }
    54. delEvent(kq, fd, kReadEvent);
    55. if (rr == 6 && !strcmp("exit\r\n", buf)) {
    56. write(fd, "good bye!\n", strlen("good bye!\n"));
    57. close(fd);
    58. return;
    59. }
    60. printf("receive bytes: %zu, i have receive your message: %s\n", rr, buf);
    61. updateEvent(kq, fd, kWriteEvent);
    62. }
    63. void handleWrite(int kq, int fd) {
    64. char *send = "i have receive your message, expect your next message\n";
    65. write(fd, send, strlen(send));
    66. delEvent(kq, fd, kWriteEvent);
    67. updateEvent(kq, fd, kReadEvent);
    68. }
    69. void loop_once(int kq, int socket_fd, int waitms) {
    70. struct timespec timeout;
    71. timeout.tv_sec = waitms / 1000;
    72. timeout.tv_nsec = (waitms % 1000) * 1000 * 1000;
    73. struct kevent *event = malloc(sizeof(struct kevent *));
    74. int retval = kevent(kq, NULL, 0, event, 20, &timeout);
    75. if (retval > 0) {
    76. printf("收到事件: %d 件\n", retval);
    77. }
    78. for (int i = 0; i < retval; i++) {
    79. struct kevent ev = event[i];
    80. uintptr_t fd = ev.ident;
    81. if (ev.filter == EVFILT_READ) {
    82. //处理可读时间
    83. if (fd == socket_fd) {
    84. handleAccept(kq, socket_fd);
    85. } else {
    86. handleRead(kq, (int) fd);
    87. }
    88. }
    89. if (ev.filter == EVFILT_WRITE) {
    90. //处理可写事件
    91. handleWrite(kq, (int) fd);
    92. }
    93. }
    94. free(event);
    95. }
    96. int main() {
    97. int port = 19999;
    98. int socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    99. struct sockaddr_in *serv_addr = malloc(sizeof(struct sockaddr_in));
    100. if (serv_addr == NULL) {
    101. printf("分配内存失败");
    102. exit(1);
    103. }
    104. serv_addr->sin_family = AF_INET;
    105. serv_addr->sin_addr.s_addr = inet_addr("127.0.0.1");
    106. serv_addr->sin_port = htons(port);
    107. //
    108. int on = 1;
    109. setsockopt(socket_fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
    110. int flags = fcntl(socket_fd, F_GETFL, 0);
    111. fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK);
    112. if (bind(socket_fd, (struct sockaddr *) serv_addr, sizeof(struct sockaddr)) < 0) {
    113. printf("bind 失败!");
    114. exit(1);
    115. }
    116. listen(socket_fd, 20);
    117. printf("使用telnet 127.0.0.1 19999 来进行测试\n");
    118. printf("输入exit来断开TCP链接\n");
    119. int queue = kqueue();
    120. //注册
    121. updateEvent(queue, socket_fd, kReadEvent);
    122. for (;;) {
    123. loop_once(queue, socket_fd, 10000);
    124. }
    125. return 0;
    126. }