且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

libevent2的hello world程序 —— 字符大写服务器

更新时间:2022-09-16 20:35:06

采用libevent2将输入的字符变成大写,然后在返回去,代码如下

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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/* For sockaddr_in */
#include <netinet/in.h>
/* For socket functions */
#include <sys/socket.h>
/* For fcntl */
#include <fcntl.h>
 
#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
 
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
 
#define MAX_LINE 16384
static const int MY_PORT = 40713;
static const int LISTEN_QUENE = 16;
 
/**
 * 将字符变成大写
 */
char DoUpper(char c)
{
    if ('a' <= c && c <= 'z')
    {
        c = c - ('a' - 'A');
    }
    return c;
}
 
/**
 * 处理输入数据的回调函数
 */
void ReadCallBack(struct bufferevent *pBuffEnt, void *pContext)
{
    struct evbuffer* pInstream = bufferevent_get_input(pBuffEnt);
    struct evbuffer* pOutstream = bufferevent_get_output(pBuffEnt);
 
    char *szLine;
    size_t n;
    // 注意,返回的line是在堆上分配的内存,用完后马上需要清理,否则产生内存泄漏
    while ((szLine = evbuffer_readln(pInstream, &n, EVBUFFER_EOL_LF)))
    {
        // 将当前行的字符串转换
        for (int i = 0; i < n; ++i)
        {
            szLine[i] = DoUpper(szLine[i]);
        }
 
        // 将当前数据输出给客户端
        evbuffer_add(pOutstream, szLine, n);
        evbuffer_add(pOutstream, "\n", 1);
        free(szLine);
    }
 
    if (evbuffer_get_length(pInstream) >= MAX_LINE) {
        /* Too long; just process what there is and go on so that the buffer
         * doesn't grow infinitely long. */
        char buf[1024];
        while (evbuffer_get_length(pInstream)) {
            int n = evbuffer_remove(pInstream, buf, sizeof(buf));
            for (int i = 0; i < n; ++i)
            {
                buf[i] = DoUpper(buf[i]);
            }
            evbuffer_add(pOutstream, buf, n);
        }
        evbuffer_add(pOutstream, "\n", 1);
    }
}
 
void ErrorCallBack(struct bufferevent *bev, short error, void *ctx)
{
    if (error & BEV_EVENT_EOF) {
        /* connection has been closed, do any clean up here */
        printf("ErrorCallBack, connection closed\n");
    } else if (error & BEV_EVENT_ERROR) {
        perror("ErrorCallBack");
    } else if (error & BEV_EVENT_TIMEOUT) {
        /* must be a timeout event handle, handle it */
        /* ... */
    }
    bufferevent_free(bev);
}
 
/**
 * 回调函数会接受三个参数
 * listener 注册的fd
 * event    注册的事件
 * arg      注册时的参数
 */
void DoAccept(evutil_socket_t nListenSock, short event, void *pArg)
{
    // 获取链接的fd
    struct sockaddr_storage oAddr;
    socklen_t nAddrLen = sizeof(oAddr);
    int nConnSock = accept(nListenSock, (struct sockaddr*)&oAddr, &nAddrLen);
    if (nConnSock < 0) {
        perror("accept");
    } else if (nConnSock > FD_SETSIZE) {
        close(nConnSock);
    } else {
        evutil_make_socket_nonblocking(nConnSock); // 设置为非堵塞的socket
 
        // 获取传入的参数——event base,自对象在DoAccpet中穿件,用于存放所有的fd
        struct event_base *pEventBase = (struct event_base*)pArg;
        // 创建一个缓冲事件,缓冲事件,顾名思义,就是当数据缓冲到一定程度,才触发,而不是只要有数据就触发
        struct bufferevent* pBuffEnt = bufferevent_socket_new(pEventBase, nConnSock, BEV_OPT_CLOSE_ON_FREE);
        bufferevent_setcb(pBuffEnt, ReadCallBack, NULL, ErrorCallBack, NULL);
        // “程度”通过高/低水位来设定
        bufferevent_setwatermark(pBuffEnt, EV_READ, 0, MAX_LINE);
        // 必须调用这句,否则enabled == false
        bufferevent_enable(pBuffEnt, EV_READ|EV_WRITE);
    }
}
 
void Run(void)
{
    // 设置地址,此服务器监听在40713上
    struct sockaddr_in oAddr;
    oAddr.sin_family = AF_INET;
    oAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    oAddr.sin_port = htons(MY_PORT);
 
    // 创建监听socket
    evutil_socket_t nListenSock = socket(AF_INET, SOCK_STREAM, 0);
    evutil_make_socket_nonblocking(nListenSock);
 
    // 将监听socket设置为地址重用
    int nOne = 1;
    setsockopt(nListenSock, SOL_SOCKET, SO_REUSEADDR, &nOne, sizeof(nOne));
 
    // 绑定端口
    if (bind(nListenSock, (struct sockaddr*)&oAddr, sizeof(oAddr)) < 0)
    {
        perror("bind");
        return;
    }
 
    // 开始监听
    if (listen(nListenSock, LISTEN_QUENE)<0)
    {
        perror("listen");
        return;
    }
 
    // 创建事件的集合对象
    struct event_base *pEventBase = event_base_new();
    if (NULL == pEventBase)
    {
        perror("event_base creating failed");
        return; /*XXXerr*/
    }
    // 将listen socket fd的read事件添加到事件集合中
    // EV_PERSIST设置监听socket的读取事件(新的连接)持续发生
    struct event* pListenEvent = event_new(pEventBase, nListenSock, EV_READ|EV_PERSIST, DoAccept, (void*)pEventBase);
 
    // 注册监听事件
    event_add(pListenEvent, NULL);
 
    // 开始主程序的循环
    event_base_dispatch(pEventBase);
}
 
int main(int c, char **v)
{
    // 设置标准输出stdout没有缓冲,直接输出任何异常
    setvbuf(stdout, NULL, _IONBF, 0);
 
    Run();
    return 0;
}


本文转自bourneli博客园博客,原文链接:http://www.cnblogs.com/bourneli/archive/2012/01/06/2315151.html,如需转载请自行联系原作者