Repository: shonm520/mu_event Branch: master Commit: 3a5da1ad8eaa Files: 33 Total size: 47.8 KB Directory structure: gitextract_05tbt9ce/ ├── README.md └── src/ ├── buffer.c ├── buffer.h ├── config.h ├── connection.c ├── connection.h ├── epoll.c ├── epoll.h ├── event.c ├── event.h ├── event_loop.c ├── event_loop.h ├── example/ │ ├── echo/ │ │ ├── echosvr │ │ ├── echosvr.c │ │ └── run.sh │ └── timer/ │ ├── run.sh │ ├── test_timer │ └── test_timer.c ├── listener.c ├── listener.h ├── logger.c ├── logger.h ├── makefile ├── ring_buffer.c ├── ring_buffer.h ├── servermanager.c ├── servermanager.h ├── tcpclient.c ├── tcpclient.h ├── testcase/ │ ├── test_buffer.c │ └── test_timer.c ├── timer.c └── timer.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: README.md ================================================ #### C语言版muduo,对muduo的部分设计做了优化 #### 之前用buffer队列实现的缓冲区,效果不是很好,后来使用了环形缓冲区 #### 下面是和muduo的部分性能对比测试,测试标准参考陈硕大佬自己的标准 https://blog.csdn.net/solstice/article/details/5864889 #### 下面是各数据时的吞吐量对比 ![吞吐量对比1](https://upload-images.jianshu.io/upload_images/9444378-b2ae69351584481a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) #### 通过使用环形缓冲区,使得吞吐量大大提高,并超过了muduo。我想除了学习到了muduo的精华,还因为目前我的程序结构比较简单,没有其他杂项的缘故 #### 下图是发送数据量为16384B,不同并发连接下的对比 ![并发时吞吐量对比2](https://upload-images.jianshu.io/upload_images/9444378-63e04366068867a7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ###### 可以看到多连接时(高并发时)muevent吞吐量也超过了muduo #### QQ讨论群:858791125 ================================================ FILE: src/buffer.c ================================================ #include #include #include "buffer.h" #include "config.h" socket_buffer* socket_buffer_new() { socket_buffer* sb = (socket_buffer*)mu_malloc(sizeof(socket_buffer)); sb->size = 0; sb->offset = 0; sb->head = sb->tail = NULL; sb->pool = (buffer_pool*)mu_malloc(sizeof(buffer_pool)); sb->pool->head = NULL; sb->pool->len = 0; return sb; } void socket_buffer_free(socket_buffer* sb) { buffer_node* head = sb->pool->head; for(; head != NULL; head = head->next) { if (head->msg) { mu_free(head->msg); head->msg = NULL; } } } buffer_node* new_buffer_node(int size) { buffer_node** pool = (buffer_node**)mu_malloc(sizeof(buffer_node*) * size); int i = 0; for (i = 0; i < size; i++) { pool[i] = (buffer_node*)mu_malloc(sizeof(buffer_node)); } for (i = 0; i < size; i++) { pool[i]->msg = NULL; pool[i]->sz = 0; pool[i]->next = pool[i + 1]; } pool[size - 1]->next = 0; return pool[0]; } int buffer_push_data(socket_buffer* sb, char* msg, int sz) //写数据到缓冲池中的新结点,然后sb指向新结点 { if (msg == NULL || sz == 0) { return 0; } buffer_pool* pool = sb->pool; buffer_node* free_node = NULL; if (pool->head == NULL) { //缓冲池已空 int len = pool->len + 1; int size = 8; if (len <= LARGE_PAGE_NODE - 3 ) { size <<= len; } else { size <<= LARGE_PAGE_NODE - 3; } free_node = new_buffer_node(size); pool->len = size; } else { free_node = pool->head; } pool->head = free_node->next; //取pool的头结点作为free_node,然后头结点指向next char* msgt = (char*)mu_malloc(sz); memcpy(msgt, msg, sz); free_node->msg = msgt; free_node->sz = sz; free_node->next = NULL; if (sb->head == NULL) { sb->head = sb->tail = free_node; } else { sb->tail->next = free_node; sb->tail = free_node; } sb->size += sz; return sb->size; } void buffer_node_release(socket_buffer* sb) //返回给缓冲池 { buffer_pool* pool = sb->pool; buffer_node* free_node = sb->head; //把头结点释放 sb->offset = 0; sb->head = free_node->next; //重置数据区 if (sb->head == NULL) { sb->tail = NULL; } free_node->next = pool->head; //把该结点加入到缓冲池 mu_free(free_node->msg); //这里放心free因为结点的指针有自己的空间 free_node->msg = NULL; free_node->sz = 0; pool->head = free_node; //重置缓冲池头结点 } char* buffer_read_spec(socket_buffer* sb, int sz, int* realSz) //读取缓冲区sz个字节 { if (sz == 0) { return NULL; } if (sb->size < sz) { //缓冲区数据不够 if (realSz) { return buffer_read_all(sb, realSz); } else { return NULL; } } buffer_pool* pool = sb->pool; sb->size -= sz; buffer_node* cur = sb->head; char* msg = (char*)mu_malloc(sz); int curLen = cur->sz - sb->offset; if (sz <= curLen) { //要读取的数据小于等于当前结点剩余的数据 memcpy(msg, cur->msg + sb->offset, sz); sb->offset += sz; if (sz == curLen) { //刚好读完就释放该结点 buffer_node_release(sb); } return msg; } else { //要读取的数据大于当前结点的数据,其余结点又有 int offset = 0; for ( ;; ) { int curLen = cur->sz - sb->offset; if (curLen >= sz) { //第二次读 memcpy(msg + offset, cur->msg + sb->offset, sz); offset += sz; sb->offset += sz; if (curLen == sz) { buffer_node_release(sb); } break; } int real_sz = (sz < curLen) ? sz : curLen; memcpy(msg + offset, cur->msg + sb->offset, real_sz); //先把当前结点剩余的的数据给读取了 offset += real_sz; buffer_node_release(sb); sz -= curLen; if (sz == 0) { break; } cur = sb->head; //由于上面释放过,这里是新的结点 if (!cur) { break; } } return msg; } return NULL; } char* buffer_read_all(socket_buffer* sb, int* retNum) //读取缓冲区所有的字节 { int total_size = sb->size; if (total_size <= 0) { return NULL; } char* msg = (char*)mu_malloc(total_size + 1); int offset = 0; while(sb->head) { buffer_node* cur = sb->head; int curLen = cur->sz - sb->offset; memcpy(msg + offset, cur->msg + sb->offset, curLen); offset += curLen; buffer_node_release(sb); //这里会重置sb->offset并重新设置头 } if (retNum) { *retNum = offset; } sb->size = 0; return msg; } int buffer_get_size(socket_buffer* sb) { if (sb) return sb->size; return 0; } ================================================ FILE: src/buffer.h ================================================ #pragma once struct buffer_node_t { char* msg; int sz; struct buffer_node_t* next; char* buf; int cap; }; struct buffer_pool_t { struct buffer_node_t* head; int len; }; struct socket_buffer_t { int size; int offset; struct buffer_node_t* head; struct buffer_node_t* tail; struct buffer_pool_t* pool; }; typedef struct buffer_node_t buffer_node; typedef struct socket_buffer_t socket_buffer; typedef struct buffer_pool_t buffer_pool; socket_buffer* socket_buffer_new(); void socket_buffer_free(socket_buffer* sb); int buffer_push_data(socket_buffer* sb, char* msg, int sz); void buffer_node_release(socket_buffer* sb); char* buffer_read_spec(socket_buffer* sb, int sz, int* realSz); char* buffer_read_all(socket_buffer* sb, int* retNum); int buffer_get_size(socket_buffer* sb); ================================================ FILE: src/config.h ================================================ #pragma once #include #ifndef bool #define bool int #endif #ifndef true #define true 1 #endif #ifndef false #define false 0 #endif #ifndef NULL #define NULL 0 #endif #define mu_malloc malloc #define mu_free free #define LARGE_PAGE_NODE 12 //buffer node 的对齐 #define MAX_EVENTS 32 //epoll_wait一次性监听最大的事件数量 #define DEFAULT_PORT 2020 //默认端口 #define MAX_LOOP 4 //max thread #define MAX_TIMER_EVENT 100 //最大定时器个数 ================================================ FILE: src/connection.c ================================================ #include #include #include #include #include #include #include #include #include #include #include #include "connection.h" #include "event_loop.h" #include "event.h" #include "config.h" #include "ring_buffer.h" #include "logger.h" /* 这里的connection仅仅指客户端连接后建立的socket connnection */ static void connection_passive_close(connection* conn); static void connection_disconnect(connection* conn); static void event_readable_callback(int fd, event* ev, void* arg); static void event_writable_callback(int fd, event* ev, void* arg); connection* connection_create(int connfd, message_callback_pt msg_cb) { connection* conn = (connection* )mu_malloc(sizeof(connection)); if (conn == NULL) { debug_ret("create connection failed, file: %s, line: %d", __FILE__, __LINE__); return NULL; } memset(conn, 0, sizeof(connection)); conn->connfd = connfd; conn->message_callback = msg_cb; //创建连接的时候没有指定EPOLLOUT,是因为在epoll水平触发的情形下指定EPOLLOUT会导致写事件一直被触发(通常写缓冲区是不满的) //这里的高效实现方式是有数据时直接调用发送,如果发现发送函数send调用之后缓冲区还有数据,则开启EPOLLOUT事件发送完毕后又关闭事件 event* ev = (event*)event_create(connfd, EPOLLIN | EPOLLPRI, event_readable_callback, conn, event_writable_callback, conn); if (ev == NULL) { debug_ret("create event failed, file: %s, line: %d", __FILE__, __LINE__); mu_free(conn); return NULL; } conn->conn_event = ev; return conn; } void connection_start(connection* conn, event_loop* loop) { if (! conn->ring_buffer_read) { conn->ring_buffer_read = ring_buffer_new(); } if (! conn->ring_buffer_write) { conn->ring_buffer_write = ring_buffer_new(); } event_add_io(loop->epoll_fd, conn->conn_event); } static int read_buffer(int fd, connection* conn) //使用了readv但是好像并没有提高效率,不过使用了栈上数据,避免了malloc,free { int nread2 = 65536; char extrabuf2[nread2]; struct iovec vec[2]; char* start = ring_buffer_readable_start(conn->ring_buffer_read); int available_bytes = ring_buffer_available_bytes(conn->ring_buffer_read); vec[0].iov_base = start; vec[0].iov_len = available_bytes; //一开始时为0,并不读到ring_buffer中去 vec[1].iov_base = extrabuf2; vec[1].iov_len = nread2; ssize_t nread = readv(fd, vec, 2); //最多读iovec结构体指定的长度,而且fd一定是非阻塞的 if (nread == 0) { return 0; } else if (nread < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { return -1; } else { debug_msg("read n < 0, fd : %d, file: %s, line: %d", conn->connfd, __FILE__, __LINE__); return -1; } } else if (nread <= available_bytes) { conn->ring_buffer_read->end += nread; return nread; } else { conn->ring_buffer_read->end += available_bytes; ring_buffer_push_data(conn->ring_buffer_read, extrabuf2, nread - available_bytes); return nread; } return -1; } static void event_readable_callback(int fd, event* ev, void* arg) { connection* conn = (connection*)arg; int nread = read_buffer(fd, conn); if (nread > 0 && conn->message_callback) { conn->message_callback(conn); } else if(nread <= 0) { connection_passive_close(conn); } } static void event_writable_callback(int fd, event* ev, void* arg) { int len = 0; connection* conn = (connection*)arg; char* msg = ring_buffer_get_msg(conn->ring_buffer_write, &len); if (msg && len > 0) { int n = send(conn->connfd, msg, len, 0); if (n > 0) { ring_buffer_release_bytes(conn->ring_buffer_write, n); len = ring_buffer_readable_bytes(conn->ring_buffer_write); if (len == 0) { //发送完所有缓冲区数据后要关闭写触发 event_disable_writing(conn->conn_event); if (conn->state == State_Closing) { connection_free(conn); //如不关闭一直会触发 conn->state = State_Closed; } } } } } static void connection_passive_close(connection* conn) { //printf("connection_passive_close!!! %d, life time is %d \n", conn->connfd, (int)time(NULL) - conn->time_on_connect); connection_disconnect(conn); } void connection_established(connection* conn) { if (conn->connected_cb) conn->connected_cb(conn); } void connection_active_close(connection* conn) { //printf("active close %d\n", conn->connfd); connection_disconnect(conn); } void connection_set_disconnect_callback(connection* conn, connection_callback_pt cb) { conn->disconnected_cb = cb; } static void connection_disconnect(connection* conn) { conn->state = State_Closing; if (ring_buffer_readable_bytes(conn->ring_buffer_write) > 0) { //收到对方关闭写的通知时,如果缓冲区还有数据要发送则等数据发送完毕后再关闭socket event_enable_writing(conn->conn_event); } else { connection_free(conn); //如不关闭一直会触发 conn->state = State_Closed; } } void connection_free(connection* conn) { if (conn->disconnected_cb) { conn->disconnected_cb(conn); } event_free(conn->conn_event); if (conn->ring_buffer_read) { ring_buffer_free(conn->ring_buffer_read); } if (conn->ring_buffer_write) { ring_buffer_free(conn->ring_buffer_write); } mu_free(conn); } void connection_send(connection *conn, char *buf, size_t len) //外部调用来发送数据 { if (ring_buffer_readable_bytes(conn->ring_buffer_write) == 0) { //缓冲区为空直接发送 int ret = send(conn->connfd, buf, len, 0); } else { printf("connection_send %d\n", len); ring_buffer_push_data(conn->ring_buffer_write, buf, len); event_enable_writing(conn->conn_event); //须开启才能发送 } } int connection_send_buffer(connection *conn) //外部调用来发送数据 { int len = 0; char* msg = ring_buffer_get_msg(conn->ring_buffer_write, &len); if (msg && len > 0) { int n = send(conn->connfd, msg, len, 0); if (n == -1) { return -1; } if (n > 0) { ring_buffer_release_bytes(conn->ring_buffer_write, n); if (n < len) { //没有发完全 event_enable_writing(conn->conn_event); //须开启才能发送 return 1; } else { return 0; } } } return -1; } ================================================ FILE: src/connection.h ================================================ #pragma once typedef struct connection_t connection; typedef void (*message_callback_pt) (connection* conn); typedef void (*connection_callback_pt)(connection *conn); typedef struct event_t event; typedef struct event_loop_t event_loop; typedef struct socket_buffer_t socket_buffer; typedef struct ring_buffer_t ring_buffer; typedef struct buffer_pool_t buffer_pool; enum { State_Closing = 1, State_Closed = 2, }; struct connection_t { int connfd; event* conn_event; //清理阶段和改变事件时用到 message_callback_pt message_callback; connection_callback_pt connected_cb; connection_callback_pt disconnected_cb; ring_buffer* ring_buffer_read; ring_buffer* ring_buffer_write; int state; void* handler; char* client_ip; //client ip int client_port; //client port int time_on_connect; }; connection* connection_create(int fd, message_callback_pt msg_cb); void connection_start(connection* conn, event_loop* loop); void connection_established(connection* conn); void connection_active_close(connection* conn); void connection_free(connection* conn); void connection_send(connection *conn, char *buf, size_t len); int connection_send_buffer(connection *conn); void connection_set_disconnect_callback(connection* conn, connection_callback_pt cb); ================================================ FILE: src/epoll.c ================================================ #include #include #include #include #include #include #include "logger.h" #include "epoll.h" #include "event.h" #include "config.h" int epoller_create() { int epoll_fd = epoll_create(1024); //大于0就好 if (epoll_fd == -1) { debug_ret("create epoll failed, file : %s, line : %d", __FILE__, __LINE__); return -1; } return epoll_fd; } void epoll_free(int fd) { close(fd); } void epoller_add(int epoll_fd, event* e) { struct epoll_event ev; ev.events = e->event_flag; ev.data.ptr = e; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, e->fd, &ev) == -1) { debug_sys("epoll_ctl add failed, file : %s, line : %d", __FILE__, __LINE__); } } void epoller_del(int epoll_fd, event* e) { struct epoll_event ev; ev.events = e->event_flag; if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, e->fd, &ev) == -1) { debug_sys("epoll_ctl del failed, file : %s, line : %d", __FILE__, __LINE__); } } void epoller_modify(int epoll_fd, event* e) { struct epoll_event ev; ev.events = e->event_flag; ev.data.ptr = e; if (epoll_ctl(epoll_fd, EPOLL_CTL_MOD, e->fd, &ev) == -1) { debug_sys("epoll_fd modify failed, file : %s, line : %d", __FILE__, __LINE__); } } struct timeval epoller_dispatch(int epoll_fd, int timeout) { struct epoll_event events[MAX_EVENTS]; int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, timeout); if (nfds == -1) { if (errno != EINTR) { debug_sys("epoll_wait failed, file : %s, line : %d", __FILE__, __LINE__); } } struct timeval now; gettimeofday(&now, NULL); int i; event* ev; for (i = 0; i < nfds; i++) { ev = (event*)events[i].data.ptr; ev->time = now; ev->active_event = events[i].events; event_handler(ev); } struct timeval end; gettimeofday(&end, NULL); return end; } ================================================ FILE: src/epoll.h ================================================ #pragma once typedef struct event_t event; int epoller_create(); void epoller_free(); void epoller_add(int fd, event* ev); void epoller_del(int fd, event* ev); void epoller_modify(int fd, event* ev); struct timeval epoller_dispatch(int fd, int timeout); ================================================ FILE: src/event.c ================================================ #include #include #include #include #include "event.h" #include "servermanager.h" #include "event_loop.h" #include "logger.h" #include "epoll.h" static void event_error_handler(event* ev) { event_free(ev); } void event_handler(event* ev) { if (ev->active_event & (EPOLLHUP | EPOLLERR)) { event_error_handler(ev); return; } if (ev->active_event & (EPOLLIN | EPOLLPRI)) { if (ev->event_read_handler) { ev->event_read_handler(ev->fd, ev, ev->r_arg); } } if (ev->active_event & EPOLLOUT) { if (ev->event_write_handler) { ev->event_write_handler(ev->fd, ev, ev->w_arg); } } } event* event_create(int fd, short event_flag, event_callback_pt read_cb, void* r_arg, event_callback_pt write_cb, void* w_arg) { event* ev = (event*)malloc(sizeof(event)); if (ev == NULL) { debug_ret("file: %s, line: %d", __FILE__, __LINE__); return NULL; } ev->fd = fd; ev->event_flag = event_flag; ev->active_event = 0; ev->event_read_handler = read_cb; ev->r_arg = r_arg; ev->event_write_handler = write_cb; ev->w_arg = w_arg; return ev; } void event_free(event* ev) { event_stop(ev); close(ev->fd); free(ev); } void event_add_io(int epoll_fd, event* ev) { epoller_add(epoll_fd, ev); ev->epoll_fd = epoll_fd; ev->is_working = 1; } void event_modify_flag(event* ev, int new_flag) { if (ev->is_working == 0) { debug_msg("epoll_fd cannot modify, because it's not working now! %s, line: %d", __FILE__, __LINE__); return; } ev->event_flag = new_flag; epoller_modify(ev->epoll_fd, ev); } void event_add_flag(event* ev, int add_flag, int plus) { int flag = ev->event_flag |= add_flag; if (plus == 0) { flag = ev->event_flag &= ~add_flag; } event_modify_flag(ev, flag); } void event_enable_writing(event* ev) { event_add_flag(ev, EPOLLOUT, 1); } void event_disable_writing(event* ev) { event_add_flag(ev, EPOLLOUT, 0); } void event_stop(event *ev) { if (ev->is_working == 0) //判断事件ev是否在epoll中,防止重复删除同一事件 return; epoller_del(ev->epoll_fd, ev); ev->is_working = 0; } ================================================ FILE: src/event.h ================================================ #pragma once #include typedef struct event_t event; typedef struct server_manager_t server_manager; typedef void (*event_callback_pt)(int fd, event* ev, void* arg); struct event_t { int fd; int event_flag; int active_event; struct timeval time; event_callback_pt event_read_handler; void* r_arg; event_callback_pt event_write_handler; void* w_arg; int is_working; int epoll_fd; }; event* event_create(int fd, short event_flag, event_callback_pt read_cb, void* r_arg, event_callback_pt write_cb, void* w_arg); int event_start(event* ev); void event_stop(event* ev); void event_free(event* ev); void event_add_io(int epoll_fd, event* ev); void event_enable_writing(event* ev); void event_disable_writing(event* ev); void event_handler(event* ev); ================================================ FILE: src/event_loop.c ================================================ #include #include #include "logger.h" #include "event_loop.h" #include "config.h" #include "epoll.h" event_loop* event_loop_create() { event_loop* loop = (event_loop*)mu_malloc(sizeof(event_loop)); if (loop == NULL) { debug_ret("create event loop failed, file : %s, line : %d", __FILE__, __LINE__); return NULL; } loop->epoll_fd = epoller_create(); if (loop->epoll_fd == -1) { debug_ret("epooler_create failed, file : %s, line : %d", __FILE__, __LINE__); mu_free(loop); return NULL; } return loop; } void event_loop_run(event_loop* loop) { int timeout = -1; while(1) { epoller_dispatch(loop->epoll_fd, timeout); } } ================================================ FILE: src/event_loop.h ================================================ #pragma once struct event_loop_t { int epoll_fd; }; typedef struct event_loop_t event_loop; event_loop* event_loop_create(); void event_loop_run(event_loop* el); ================================================ FILE: src/example/echo/echosvr.c ================================================ #include #include "servermanager.h" #include "connection.h" #include "listener.h" #include "ring_buffer.h" #include "config.h" void onMessage(connection *conn) { int size = 0; char* msg = ring_buffer_get_msg(conn->ring_buffer_read, &size); printf("read all : %s, %d\n", msg, size); char buf[] = "abcd"; connection_send(conn, buf, sizeof(buf) - 1); connection_send(conn, msg, size); } void onConnection(connection* conn) { printf("connected!!! ip:port %s:%d\n", conn->client_ip, conn->client_port); } int main(int argc, char* argv[]) { int port = DEFAULT_PORT; int thread_num = MAX_LOOP; if (argc >= 2) port = atoi(argv[1]); if (argc >= 3) thread_num = atoi(argv[2]); printf("port, thread_num is %d, %d \n", port, thread_num); server_manager *manager = server_manager_create(port, thread_num); inet_address addr = addr_create("any", port); listener_create(manager, addr, onMessage, onConnection); server_manager_run(manager); return 0; } ================================================ FILE: src/example/echo/run.sh ================================================ rm -f echosvr gcc -o echosvr *.c ../../*.c -lpthread -g -I ../../ ================================================ FILE: src/example/timer/run.sh ================================================ rm test_timer echo "rm" gcc -o test_timer test_timer.c ../../*.c -lpthread -g -I ../../ ================================================ FILE: src/example/timer/test_timer.c ================================================ #include #include "config.h" #include "connection.h" #include "servermanager.h" #include "listener.h" #include "timer.h" static void timer_cb(void* arg) { printf("timer tick 2 seconds!!!!\n\n"); } static void timer_cb1(void* arg) { printf("timer tick 1500 miseconds!!!!\n\n"); } static void timer_cb_once(void* arg) { printf("timer tick once!!!!\n\n"); } int main(int argc, char* argv[]) { int port = DEFAULT_PORT; int thread_num = MAX_LOOP; if (argc >= 2) port = atoi(argv[1]); if (argc >= 3) thread_num = atoi(argv[2]); server_manager *manager = server_manager_create(port, thread_num); inet_address addr = addr_create("any", port); listener_create(manager, addr, NULL, NULL); timer ti; ti.type = TIMER_OPT_REPEAT; ti.time_out = 2000; ti.callback = timer_cb; ti.arg = NULL; server_manager_add_timer(manager, ti); ti.type = TIMER_OPT_REPEAT; ti.time_out = 1500; ti.callback = timer_cb1; server_manager_add_timer(manager, ti); ti.type = TIMER_OPT_ONCE; ti.time_out = 5000; ti.callback = timer_cb_once; server_manager_add_timer(manager, ti); server_manager_run(manager); return 0; } ================================================ FILE: src/listener.c ================================================ #include #include #include #include #include #include #include #include #include #include #include "listener.h" #include "servermanager.h" #include "event.h" #include "connection.h" #include "event_loop.h" #include "logger.h" extern event_loop *g_loops[]; inet_address addr_create(const char *ip, int port) { if (ip == NULL) debug_quit("addr_create failed, ip is null, file: %s, line: %d", __FILE__, __LINE__); inet_address new_addr; memset(&new_addr.addr, 0, sizeof(new_addr.addr)); new_addr.addr.sin_family = AF_INET; if (strcmp(ip, "any") == 0) new_addr.addr.sin_addr.s_addr = htonl(INADDR_ANY); else if(inet_pton(AF_INET, ip, &new_addr.addr.sin_addr) <= 0) debug_quit("inet_pton failed, file: %s, line: %d", __FILE__, __LINE__); new_addr.addr.sin_port = htons(port); return new_addr; } static void default_disconnected_callback(connection* conn) { } static void event_accept_callback(int listenfd, event* ev, void* arg) { server_manager *manager = (server_manager *)arg; inet_address client_addr; socklen_t clilen = sizeof(client_addr.addr); int connfd = accept(listenfd, (struct sockaddr *)&client_addr.addr, &clilen); if (connfd < 0) { int save = errno; if (save == EAGAIN || save == ECONNABORTED || save == EINTR || save == EPROTO || save == EPERM || save == EMFILE) { return; } else { debug_sys("accept failed, file: %s, line: %d", __FILE__, __LINE__); } } fcntl(connfd, F_SETFL, fcntl(connfd, F_GETFL) | O_NONBLOCK); static int i = 0; if (i >= manager->loop_num) i = 0; event_loop* loop = NULL; if (manager->loop_num == 0) { //如果没有开启线程则用主线程的 loop = manager->loop; } else { loop = g_loops[i++]; } int tcp_nodelay = 1; //不等对方发送ack直接发送减少延迟 setsockopt(connfd, IPPROTO_TCP, TCP_NODELAY,(const void *) &tcp_nodelay, sizeof(int)); connection *conn = connection_create(connfd, manager->msg_callback); //后面的参数是指有消息时的用户回调 if (conn == NULL) { debug_quit("create connection failed, file: %s, line: %d", __FILE__, __LINE__); } conn->client_ip = inet_ntoa(client_addr.addr.sin_addr); conn->client_port = ntohs(client_addr.addr.sin_port); //used for debug conn->time_on_connect = time(NULL); conn->disconnected_cb = default_disconnected_callback; if (manager->new_connection_callback) { conn->connected_cb = manager->new_connection_callback; connection_established(conn); } connection_start(conn, loop); } #define ERR_SOCKET 1 #define ERR_BIND 2 #define ERR_LISTEN 3 #define ERR_EVENT 4 listener* listener_create(server_manager* manager, inet_address ls_addr, message_callback_pt msg_cb, connection_callback_pt new_con_cb) { listener* ls = (listener*)malloc(sizeof(listener)); if (ls == NULL) { debug_ret("create listener failed, file: %s, line: %d", __FILE__, __LINE__); return NULL; } ls->listen_addr = ls_addr; manager->msg_callback = msg_cb; manager->new_connection_callback = new_con_cb; int err_code = 0; event* lev = NULL; int listen_fd; do { listen_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); //创建非阻塞套接字 if (listen_fd < 0) { err_code = ERR_SOCKET; break; } int opt = 1; setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); int ret = bind(listen_fd, (struct sockaddr *)&ls_addr.addr, sizeof(ls_addr.addr)); if (ret < 0) { err_code = ERR_BIND; break; } ret = listen(listen_fd, SOMAXCONN); if (ret < 0) { err_code = ERR_LISTEN; break; } lev = event_create(listen_fd, EPOLLIN | EPOLLPRI, event_accept_callback, manager, NULL, NULL); //后面参数是写事件回调及其参数,由于这里是监听socket不需要 if (lev == NULL) { err_code = ERR_EVENT; break; } } while(0); if (err_code != 0) { debug_ret("create listener failed, error code is %d, file: %s, line: %d", err_code, __FILE__, __LINE__); if (listen_fd > 0) { close(listen_fd); } free(ls); return NULL; } else { event_add_io(manager->loop->epoll_fd, lev); } return ls; } ================================================ FILE: src/listener.h ================================================ #pragma once #include #include /* 封装的IPv4地址和port */ typedef struct inet_addr_t { struct sockaddr_in addr; } inet_address; inet_address addr_create(const char *ip, int port); typedef struct connection_t connection; typedef void (*connection_callback_pt)(connection *conn); typedef void (*message_callback_pt)(connection *conn); typedef struct listener_t listener; struct listener_t { inet_address listen_addr; //event* ls_event; }; typedef struct server_manager_t server_manager; listener* listener_create(server_manager* manager, inet_address ls_addr, message_callback_pt msg_cb, connection_callback_pt new_con_cb); void listener_free(listener* ls); ================================================ FILE: src/logger.c ================================================ #include #include #include #include #include #define MAXLINE 128 #define DBG_PRINTF debug_print static void debug_print(int, const char *, va_list); /* 系统调用非致命错误 * 打印用户信息 + errno信息后返回 */ void debug_ret(const char *fmt, ...) { va_list ap; va_start(ap, fmt); DBG_PRINTF(1, fmt, ap); va_end(ap); } /* 系统调用致命错误 * 打印用户信息 + errno信息后终止进程 */ void debug_sys(const char *fmt, ...) { va_list ap; va_start(ap, fmt); DBG_PRINTF(1, fmt, ap); va_end(ap); exit(1); } /* 非系统调用致命错误 * 打印用户信息后终止进程 */ void debug_quit(const char *fmt, ...) { va_list ap; va_start(ap, fmt); DBG_PRINTF(0, fmt, ap); va_end(ap); exit(1); } /* 普通用户信息 */ void debug_msg(const char *fmt, ...) { va_list ap; va_start(ap, fmt); DBG_PRINTF(0, fmt, ap); va_end(ap); } /* 打印核心函数 */ static void debug_print(int errnoflag, const char *fmt, va_list ap) { int errno_save, n; char buf[MAXLINE + 1]; errno_save = errno; vsnprintf(buf, MAXLINE, fmt, ap); /* safe */ n = strlen(buf); if (errnoflag) snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save)); strcat(buf, "\n"); fflush(stderr); fputs(buf, stderr); /* no newline */ fflush(stderr); } ================================================ FILE: src/logger.h ================================================ #pragma once void debug_ret(const char *fmt, ...); void debug_sys(const char *fmt, ...); void debug_msg(const char *fmt, ...); void debug_quit(const char *fmt, ...); ================================================ FILE: src/makefile ================================================ src = $(wildcard ./*c) obj = $(patsubst ./%.c, ./%.o, $(src)) LIB = libmuevent.a CC = gcc CFLAGS := -g -lpthread %.o:%.c $(CC) $(CFLAGS) -c $< -o $@ $(LIB):$(obj) rm -f $@ ar cr $@ $(obj) rm -f $(obj) .PHONY:clean clean: rm -f $(obj) $(LIB) .PHONY:cleantemp cleantemp: rm -f $(obj) ================================================ FILE: src/ring_buffer.c ================================================ #include #include #include "ring_buffer.h" #include "config.h" ring_buffer* ring_buffer_new() { ring_buffer* rb = (ring_buffer*)mu_malloc(sizeof(ring_buffer)); memset(rb, 0, sizeof(ring_buffer)); return rb; } void ring_buffer_free(ring_buffer* rb) { if (rb->msg) { mu_free(rb->msg); } } void ring_buffer_push_data(ring_buffer* rb, char* msg, int size) { int used = rb->end - rb->start; int available = rb->cap - used; if (available < size) { //可用数据不足了 if (rb->start > size) { //可以塞前面 memmove(rb->msg, rb->msg + rb->start, used); rb->start = 0; memcpy(rb->msg + used, msg, size); rb->end = used + size; } else { rb->cap = rb->cap * 2 + size; char* new_msg = (char*)mu_malloc(rb->cap); if (used > 0 ) { memcpy(new_msg, rb->msg + rb->start, used); } memcpy(new_msg + used, msg, size); if (rb->msg) { //刚开始非空 mu_free(rb->msg); } rb->msg = new_msg; rb->start = 0; rb->end = size + used; } } else { memcpy(rb->msg + rb->end, msg, size); rb->end += size; } } char* ring_buffer_readable_start(ring_buffer* rb) { return rb->msg + rb->start; } char* ring_buffer_get_msg(ring_buffer* rb, int* len) { char* msg = rb->msg + rb->start; if (len) { int ocuSize = rb->end - rb->start; *len = ocuSize; } if (rb->end == rb->start) { msg = NULL; } return msg; } int ring_buffer_readable_bytes(ring_buffer* rb) { int ocuSize = rb->end - rb->start; return ocuSize; } int ring_buffer_available_bytes(ring_buffer* rb) { return rb->cap - rb->end; } void ring_buffer_release_bytes(ring_buffer* rb, int size) { if (rb->msg + rb->start) { memset(rb->msg + rb->start, 0, size); } rb->start += size; if (rb->start == rb->end) { rb->start = rb->end = 0; } } ================================================ FILE: src/ring_buffer.h ================================================ #pragma once struct ring_buffer_t { int start; int end; int cap; char* msg; }; typedef struct ring_buffer_t ring_buffer; ring_buffer* ring_buffer_new(); void ring_buffer_free(ring_buffer* rb); void ring_buffer_push_data(ring_buffer* rb, char* msg, int size); char* ring_buffer_readable_start(ring_buffer* rb); int ring_buffer_readable_bytes(ring_buffer* rb); void ring_buffer_release_bytes(ring_buffer* rb, int size); char* ring_buffer_get_msg(ring_buffer* rb, int* len); int ring_buffer_available_bytes(ring_buffer* rb); ================================================ FILE: src/servermanager.c ================================================ #include #include #include #include #include #include "servermanager.h" #include "event_loop.h" #include "epoll.h" #include "config.h" #include "timer.h" #include "logger.h" event_loop *g_loops[MAX_LOOP]; int started_loop = 0; pthread_spinlock_t lock; void* spawn_thread(void *arg) { int i = (long)arg; g_loops[i] = event_loop_create(); pthread_spin_lock(&lock); started_loop++; pthread_spin_unlock(&lock); event_loop_run(g_loops[i]); return 0; } server_manager* server_manager_create(int port, int thread_num) { pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE); server_manager* manager = (server_manager*)malloc(sizeof(server_manager)); if (manager == NULL) { debug_ret("create server_manager failed, file: %s, line: %d", __FILE__, __LINE__); return NULL; } manager->listen_port = port; manager->loop = event_loop_create(); if (manager->loop == NULL) { debug_ret("create epoller failed, file: %s, line: %d", __FILE__, __LINE__); mu_free(manager); return NULL; } signal(SIGPIPE, SIG_IGN); if (thread_num < 0 || thread_num > MAX_LOOP) { thread_num = MAX_LOOP; } manager->loop_num = thread_num; pthread_t tid; long long i = 0; for (i = 0; i < thread_num; i++) { pthread_create(&tid, NULL, spawn_thread, (void *)i); } while(true) { //等event_loop全部create完毕 pthread_spin_lock(&lock); if (started_loop == thread_num) { pthread_spin_unlock(&lock); break; } pthread_spin_unlock(&lock); } pthread_spin_destroy(&lock); manager->timer_manager = timer_manager_create(); return manager; } void server_manager_time_event(server_manager* manager, int timeout) { timer_manager* tm = manager->timer_manager; if (!tm || tm->size <= 0) { return; } timer_manager_update(tm, timeout); timer* top = tm->top; while(top->time_left <= 0) { timer ti = timer_manager_pop(tm); if (ti.type == TIMER_OPT_ONCE) { ti.callback(ti.arg); } else if (ti.type == TIMER_OPT_REPEAT) { server_manager_add_timer(manager, ti); ti.callback(ti.arg); } top = tm->top; } } bool calc_timeout(server_manager* manager, int* timeout) { timer_manager* tm = manager->timer_manager; if (tm && tm->size > 0 && tm->top) { *timeout = tm->top->time_left; return true; } *timeout = -1; return false; } void server_manager_add_timer(server_manager* manager, timer ti) { timer_manager* tm = manager->timer_manager; if (!tm) { return ; } timer_manager_push(tm, ti); } void server_manager_run(server_manager* manager) { int timeout = -1; while(1) { bool has_timeout = calc_timeout(manager, &timeout); struct timeval now; gettimeofday(&now, NULL); struct timeval trigger_time = epoller_dispatch(manager->loop->epoll_fd, timeout); // int64_t diff = (trigger_time.tv_sec - now.tv_sec) * 1000 * 1000 + (trigger_time.tv_usec - now.tv_usec); timeout = diff / 1000; if (has_timeout) { server_manager_time_event(manager, timeout); //已经过去了多少毫秒 } } } ================================================ FILE: src/servermanager.h ================================================ #pragma once typedef struct connection_t connection; typedef void (*connection_callback_pt)(connection *conn); typedef void (*message_callback_pt)(connection *conn); typedef struct event_loop_t event_loop; typedef struct timer_ timer; typedef struct timer_manager_t timer_manager; struct server_manager_t { int epoll_fd; int listen_port; int loop_num; event_loop* loop; connection_callback_pt new_connection_callback; message_callback_pt msg_callback; timer_manager* timer_manager; }; typedef struct server_manager_t server_manager; server_manager* server_manager_create(int port, int thread_num); void server_manager_run(server_manager* manager); void server_manager_add_timer(server_manager* manager, timer ti); ================================================ FILE: src/tcpclient.c ================================================ #include #include #include #include #include #include #include #include "tcpclient.h" #include "config.h" #include "event_loop.h" #include "event.h" #include "connection.h" #include "logger.h" tcpclient* tcpclient_create(const char* ip, short port) { tcpclient* cli = (tcpclient*)mu_malloc(sizeof(tcpclient)); int socket_fd = socket(AF_INET, SOCK_STREAM, 0); if (socket_fd < 0) { debug_ret("create socket failed, file: %s, line: %d", __FILE__, __LINE__); return NULL; } cli->connfd = socket_fd; cli->ip = (char*)ip; cli->port = port; signal(SIGPIPE, SIG_IGN); return cli; } static void default_disconnect_callback(connection* conn) { printf("client disconnected#######\n\n"); } int tcpclient_connect(tcpclient* cli, connected_callback_pt connected_cb, message_callback_pt msg_cb) { struct sockaddr_in server_address; memset( &server_address, 0, sizeof(server_address)); server_address.sin_family = AF_INET; inet_pton( AF_INET, cli->ip, &server_address.sin_addr); server_address.sin_port = htons(cli->port); int ret = connect(cli->connfd, (struct sockaddr*)&server_address, sizeof(server_address)); if (ret == -1) { debug_sys("connect failed, file: %s, line: %d", __FILE__, __LINE__); return -1; } connection *conn = connection_create(cli->connfd, msg_cb); //后面的参数是指有消息时的用户回调 if (conn == NULL) { debug_quit("create connection failed, file: %s, line: %d", __FILE__, __LINE__); } conn->disconnected_cb = default_disconnect_callback; connected_cb(conn); return 0; } void tcpclient_run(event_loop* loop) { event_loop_run(loop); } ================================================ FILE: src/tcpclient.h ================================================ #pragma once typedef struct event_loop_t event_loop; typedef struct connection_t connection; typedef void (*message_callback_pt)(connection *conn); struct tcpclient_t { int connfd; char* ip; short port; event_loop* loop; //message_callback_pt msg_callback; }; typedef struct tcpclient_t tcpclient; tcpclient* tcpclient_create(const char* ip, short port); typedef void (*connected_callback_pt)(connection *conn); int tcpclient_connect(tcpclient* cli, connected_callback_pt connected_cb, message_callback_pt msg_cb); int tcpclient_send(tcpclient* cli); void tcpclient_run(event_loop* loop); ================================================ FILE: src/testcase/test_buffer.c ================================================ #include #include #include "../buffer.h" int main() { socket_buffer* sb = socket_buffer_new(); buffer_push_data(sb, "123456", 6); buffer_push_data(sb, "abcdef", 6); buffer_push_data(sb, "xyzmnl", 6); int size = 0; char* msg = buffer_read_spec(sb, 28, NULL); printf("read %s, %d\n", msg, size); printf("aft read sb->size is %d\n\n", sb->size); msg = buffer_read_spec(sb, 18, &size); printf("read %s, %d\n", msg, size); printf("aft read sb->size is %d\n\n", sb->size); msg = buffer_read_all(sb, &size); printf("read %s, %d\n", msg, size); printf("aft read sb->size is %d\n\n", sb->size); socket_buffer_free(sb); return 0; } ================================================ FILE: src/testcase/test_timer.c ================================================ #include #include "../timer.h" int main() { timer_manager* t = timer_manager_create(); timer* t1 = timer_new(500); timer* t2 = timer_new(250); timer* t3 = timer_new(360); timer* t4 = timer_new(180); timer* t5 = timer_new(300); timer* t6 = timer_new(180); timer_manager_push(t, *t1); timer_manager_push(t, *t2); timer_manager_push(t, *t3); timer_manager_push(t, *t4); timer_manager_push(t, *t5); timer_manager_push(t, *t6); //timer* top = timer_manager_get_top(t); //printf("t top is %d\n", top->time_out); timer top = timer_manager_pop(t); printf("t top is %d\n", top.time_out); top = timer_manager_pop(t); printf("t top is %d\n", top.time_out); top = timer_manager_pop(t); printf("t top is %d\n", top.time_out); top = timer_manager_pop(t); printf("t top is %d\n", top.time_out); top = timer_manager_pop(t); printf("t top is %d\n", top.time_out); top = timer_manager_pop(t); printf("t top is %d\n", top.time_out); timer_manager_push(t, *t3); timer_manager_push(t, *t3); timer_manager_push(t, *t3); top = timer_manager_pop(t); printf("t top is %d\n", top.time_out); timer_manager_free(t); return 0; } ================================================ FILE: src/timer.c ================================================ #include #include "timer.h" #include "config.h" timer_manager* timer_manager_create() { int size = sizeof(timer_manager); timer_manager* m = (timer_manager*)mu_malloc(size); if (NULL == m) { return NULL; } memset(m, 0, size); m->cap = MAX_TIMER_EVENT; m->queue0 = (timer**)mu_malloc(size * m->cap); m->queue1 = (timer**)mu_malloc(size * m->cap); memset(m->queue0, 0, size * m->cap); memset(m->queue1, 0, size * m->cap); return m; } void timer_manager_free(timer_manager* m) { if (m) { timer** queue = m->queue0; if (m->index == 1) { queue = m->queue1; } int i = 0; for (; i < m->cap ; i++) { if (queue[i]) { mu_free(queue[i]); } else { break; } } if(m->queue0) mu_free(m->queue0); if(m->queue1) mu_free(m->queue1); } } timer* timer_new(int utime) { timer* t = (timer*)malloc(sizeof(timer)); memset(t, 0, sizeof(timer)); t->time_out = utime; return t; } void timer_manager_push(timer_manager* manager, timer ti) { int size = manager->size; if (size >= manager->cap) { timer** temp0 = manager->queue0; timer** temp1 = manager->queue1; int size_of_ptr = sizeof(timer*); manager->queue0 = (timer**)mu_malloc(size_of_ptr * manager->cap * 2); manager->queue1 = (timer**)mu_malloc(size_of_ptr * manager->cap * 2); memset(manager->queue0, 0, size_of_ptr * manager->cap * 2); memset(manager->queue1, 0, size_of_ptr * manager->cap * 2); //memcpy(manager->queue0, temp0, manager->cap); //memcpy(manager->queue1, temp1, manager->cap); if (manager->index == 0) { int i = 0; for (; i < manager->size; i++) { manager->queue0[i] = temp0[i]; } } else { int i = 0; for (; i < manager->size; i++) { manager->queue1[i] = temp1[i]; } } mu_free(temp0); mu_free(temp1); manager->cap *= 2; } ti.time_left = ti.time_out; timer* pti = (timer*)mu_malloc(sizeof(timer)); *pti = ti; if (manager->top) { if (pti->time_left < manager->top->time_left) { //替换最小的 manager->top = pti; manager->top_index = size; } } else { manager->top = pti; } if (manager->index == 0) { manager->queue0[manager->size++] = pti; } else { manager->queue1[manager->size++] = pti; } } timer timer_manager_pop(timer_manager* manager) { timer ti; ti.time_out = 0; if (manager == NULL) { return ti; } if (manager->size <= 0) { return ti; } timer ret = *manager->top; if (manager->size == 1) { manager->top = NULL; manager->size = 0; return ret; } mu_free(manager->top); manager->top = NULL; int top_index = manager->top_index; if (manager->size > 1) { timer* top = NULL; timer** queue0; timer** queue1; if (manager->index == 0) { queue0 = manager->queue0; queue1 = manager->queue1; } else { queue0 = manager->queue1; queue1 = manager->queue0; } manager->index = (manager->index + 1) % 2; int i = 0; int j = 0; for (; i < manager->cap; i++) { if (i < manager->size) { if (i == top_index) { continue; } queue1[j] = queue0[i]; if (top == NULL) { top = queue0[i]; manager->top_index = 0; } else { if (queue0[i]->time_left < top->time_left) { top = queue0[i]; manager->top_index = j; } } j++; } else { queue0[i] = NULL; queue1[i] = NULL; } } manager->top = top; } manager->size -= 1; return ret; } timer timer_manager_get_top(timer_manager* manager) { return *manager->top; } void timer_manager_update(timer_manager* manager, int timeout) { timer** queue = NULL; if (manager->index == 0) { queue = manager->queue0; } else { queue = manager->queue1; } int i = 0; for (; i < manager->size; i++) { timer* ti = queue[i]; ti->time_left -= timeout; } } ================================================ FILE: src/timer.h ================================================ #pragma once typedef void (*timeout_callback_pt)(void *arg); enum TimerOptions { TIMER_OPT_NONE, // 超时不处理 TIMER_OPT_ONCE, // 超时处理一次 TIMER_OPT_REPEAT // 超时重复处理 }; struct timer_ { int time_out; //单位毫秒 int time_left; enum TimerOptions type; timeout_callback_pt callback; void* arg; }; typedef struct timer_ timer; struct timer_manager_t { timer* top; timer** queue0; timer** queue1; int index; int size; int cap; int top_index; }; typedef struct timer_manager_t timer_manager; timer_manager* timer_manager_create(); void timer_manager_free(timer_manager* m); timer* timer_new(int utime); void timer_manager_push(timer_manager* manager, timer ti); timer timer_manager_pop(timer_manager* manager); timer timer_manager_get_top(timer_manager* manager); void timer_manager_update(timer_manager* manager, int timeout);