APUE course source code
guowenxue
yesterday 7b55c92f8d1401a93c8fd8e342da271dce742000
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*********************************************************************************
 *      Copyright:  (C) 2025 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  epoll.c
 *    Description:  This file is epoll example.
 *
 *        Version:  1.0.0(11/06/2025)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "11/06/2025 10:33:45 AM"
 *
 ********************************************************************************/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
 
#define MAX_EVENTS  2 /*  监听 STDIN + sockfd */
 
int main(void)
{
    int                 sockfd;
    struct sockaddr_in  addr;
    int                 nfds;
    int                 reuse = 1;
 
    int                 epfd;
    struct epoll_event  ev, events[MAX_EVENTS];
 
    sockfd = socket(AF_INET, SOCK_STREAM, 0); /* 创建套接字 */
 
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8888);
    addr.sin_addr.s_addr = INADDR_ANY;
 
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
    bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
    listen(sockfd, 5);
 
    /* 创建 epoll 实例 */
    epfd = epoll_create1(0);
    if (epfd < 0)
    {
        printf("epoll_create1 failure: %s\n", strerror(errno));
        return 1;
    }
 
    /* 将 STDIN(键盘) 添加到 epoll 监控列表 */
    ev.events = EPOLLIN;
    ev.data.fd = STDIN_FILENO;
    if (epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) < 0)
    {
        printf("epoll_ctl add stdin failure: %s\n", strerror(errno));
        return 2;
    }
 
    /* 将 socket 添加到 epoll 监控列表 */
    ev.events = EPOLLIN;
    ev.data.fd = sockfd;
    if (epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev) < 0)
    {
        printf("epoll_ctl add sockfd failure: %s\n", strerror(errno));
        return 2;
    }
 
    printf("epoll() monitor socket[8888] and stdin now...\n");
 
    while (1)
    {
        /* 调用 epoll 等待事件发生 */
        nfds = epoll_wait(epfd, events, MAX_EVENTS, 10000);
        if (nfds == -1)
        {
            printf("epoll error: %s\n", strerror(errno));
            break;
        }
        else if (nfds == 0)
        {
            printf("timeout...\n");
            continue;
        }
 
        /* 程序走到这里说明nfds>0,即监听的文件描述符中有事件发生了. */
 
        /* 有多少个文件描述符发生了事件就处理多少个 */
        for (int i = 0; i < nfds; i++)
        {
            int fd = events[i].data.fd;
 
            if (fd == STDIN_FILENO)
            {
                char buf[128];
                ssize_t n = read(STDIN_FILENO, buf, sizeof(buf) - 1);
                if (n > 0)
                {
                    buf[n] = '\0';
                    printf("You typed in keyboard: %s\n", buf);
                }
            }
            else if (fd == sockfd)
            {
                int client = accept(sockfd, NULL, NULL);
                if (client >= 0)
                {
                    printf("Accept and close connection: %d\n", client);
                    close(client);
                }
            }
        }
    }
 
    close(sockfd);
    return 0;
}