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