采用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; }