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


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

    /* 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;
    }
  • 相关阅读:
    为什么要有handler机制
    安卓五种数据存储的方式
    Activity生命周期详解
    JS的一些简单实例用法
    JSP 中的EL表达式详细介绍
    JSP九大内置对象和四个作用域
    JS实现---图片轮播效果
    实现 鼠标移动到表格的某行 该行换背景 ---myEclipse编写
    JS 菜单收拉样式
    spring中aware接口的
  • 原文地址:https://www.cnblogs.com/bourneli/p/2315151.html
Copyright © 2020-2023  润新知