Day1: Lars基础服务功能+内存管理

1 回显功能

1.1 创建tcp_server

1.1.1 tcp构造函数

        实现socket创建过程,即创建、绑定、监听,需要信号忽略机制(如SIGHUP, SIGPIPE)。

//构造函数
tcp_server::tcp_server(const char* ip, __uint128_t port)
{   
    //0.忽略一些信号 SIGHUB, SIGPIPE
    if(singal(SIGHUP, SIG_IGN)==SIG_ERR){
        fprintf(stderr, "signal ingore SIGHUB\n");
    }
    //1.创建socket
    _sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(_sockfd==-1)
    {
        fprintf(stderr, "tcp::server socket()\n");
        exit(1);
    }
    
    //2.初始化服务器地址
    struct sockaddr_in server_addr;
    ZeroMemory(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    inet_pton(ip, &server_addr.sin_addr);
    server_addr.sin_port = htons(port);

    //设置socket可以重复监听
    int op=1;
    if(setsockopt(_sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&op, sizeof(op))<0){
        fprintf(stderr, "set socketopt error\n");
        exit(1);
    }

    //3.绑定端口
    if(bind(_sockfd, (const struct sockaddr*)&server_addr, sizeof(server_addr))<0)
    {
        fprintf(stderr, "bind error\n");
        exit(1);
    }
    
    //4.监听
    if(listen(_sockfd, 500)==-1)
    {
        fprintf(stderr, "listen error\n");
        exit(1);
    }
}
1.1.2 do_accept

       (1) accept操作,接受客服端发送信息。当accept返回值为-1,需要对errno的具体数值来进行处理。

        (2) while循环, 发送“lars hello”给客户端

//开始提供创建链接的服务
void tcp_server::do_accept(){
    int connfd;
    while(1){
        //1 accept
        connfd = accept(_sockfd, (struct sockaddr*)&_connaddr, &_addrlrn);
        if(connfd==-1)
        {
            if(errno==EINTR){
                fprintf(stderr, "accept error = EINTR\n"); //中断错误
                continue;
            }
            else if(errno==EAGAIN){
                fprintf(stderr, "accept error = EAGAIN\n"); 
                break;
            }
            else if(errno == EMFILE){
                //建立连接过多,资源不够
                fprintf(stderr, "accpet error = EMFILE\n");
                continue;
            }
            else exit(1);
        }else{
            //accept success
            //添加心跳机制...
            //添加消息队列机制...
            
            //回显
            int writed;
            const char* data = "hello lars\n";
            do{
                writed = write(connfd, data, strlen(data)+1);
            }while(writed==-1&&errno==EINTR);

            if(writed>0){
                //succ
                cout << "succeed!" << endl;
            }
        }
    }
}

2 内存管理

2.1 内存块结构io_buf

2.1.1 属性

        每个内存块的属性包括:容量(capacity),有效数据长度(length),未处理的数据首地址(head), 当前内存块首地址(data),构造链表结构io_buf类型指针next。

/*定义一个buffer 一块内存的数据结构体*/
class io_buf{
    public:
    io_buf(int size); //构造函数,创建一个size大小的buf
    //清空数据
    void clear();
    //处理长度为数据,移动head
    void pop(int len); //len表示已经处理的数据的长度

    //将已经处理的数据清空,从内存删除,降维处理的数据移至buf的首地址,length减小
    void adjust();

    //将其他的io_buf对象拷贝到自己
    void copy(const io_buf *other);

    int capacity; //当前buf的总容量
    int length;   //当前buf有效数据长度
    int head;     //当前未处理有效数据的头部索引
    char *data;   //当前buf的内存首地址
    io_buf *next;//存在多个io_buf  采用链表的形式进行管理
};
2.1.2 方法

        clear():清空内存,不是物理回收,而是指针清空。

        pop(int len):已经处理了长度为len的数据。

        adjust():将head充值,将有效的数据前置到data指针下。

        copy(io_buf *other):将other的有效数据拷贝到自身中。
        

//创建一个size大小的buf
io_buf::io_buf(int size){
    capacity = size;
    length=0;
    head=0;
    next=NULL;

    data = new char[size];
    assert(data!=NULL); //如果data==NULL, 则程序直接退出
}

//清空数据
void io_buf::clear()
{
    length = head =0;
}

//处理长度为数据,移动head,len表示已经处理的数据的长度
void io_buf::pop(int len)
{
    length -= len;
    head += len;

} 

//将已经处理的数据清空,从内存删除,降维处理的数据移至buf的首地址,length减小
void io_buf::adjust()
{
    if(head!=0)
    {
        //length==0代表所有数据已经处理完
        if(length!=0)
            memmove(data, data+head, length);
        head=0;
    }
}

//将其他待处理部分的io_buf对象拷贝到自己
void io_buf::copy(const io_buf *other)
{
    memcpy(data, other->data+other->head, other->length);
    head=0;
    length = other->length;
}

2.2内存池结构io_pool

2.2.1 属性

        内存池的数据句柄map<key, value>----><内存块刻度,当前刻度下所挂载的io_buf链表>;

        内存池的总体大小total_num;

typedef std::unordered_map<int, io_buf*> pool_t;
//定义一些内存刻度
enum MEM_CAP{
    m4k = 4096,
    m16k = 16384,
    m64k = 65536,
    m128k = 262144,
    m1M = 1048576,
    m4M = 4194304,
    m8M = 8388608 
};

//总内存池大小限制
#define MEM_LIMIT (5U*1024*1024)

class buf_pool
{
public:
    //初始化单例对象
    static void init(){
        _instance = new buf_pool();
    }
    //提供一个静态获取instance的方法
    static buf_pool* instance()
    {   
        pthread_once(&_once, init); //保证init方法在进程的生命周期只执行一次
        return _instance;
    }

    //从内存池申请一块内存
    io_buf *alloc_buf(int N);
    io_buf *alloc_buf();

    //重置io_buf放回pool
    void revert(io_buf* buffer);

    void buf_pool::make_io_buf_list(int cap, int num);
private:
    //==============创建单例================
    //构造函数私有化
    buf_pool(); 
    buf_pool(const buf_pool&);
    const buf_pool& operator = (const buf_pool&);

    //单例对象
    static buf_pool*_instance; 

    //保证创建单例的一个方法,全局只执行一次
    static pthread_once_t _once;

    //==============buf_pool属性==============
    //存放所有io_buf的map句柄
    pool_t _pool; //<key, value>=<内存块刻度, 当前刻度下所挂载的io_buf链表>
    //当前内存池总体大小
    uint64_t _total_mem;
    //保护pool map增删改查的锁
    static pthread_mutex_t _mutex;

};
2.2.2 方法

        构造函数buff_pool():初始化全部内存

buf_pool::buf_pool():_total_mem(0)
{
    make_io_buf_list(m4k, 5000);
    make_io_buf_list(m16k, 5000);
    make_io_buf_list(m64k, 5000);
    make_io_buf_list(m128k, 5000);
    make_io_buf_list(m1M, 5000);
    make_io_buf_list(m4M, 5000);
    make_io_buf_list(m8M, 5000);

}

        io_buf  *buf_pool::alloc_buf(int N):得到一个io_buf的方法,即开辟一个io_buf

//从内存池申请一块内存
io_buf *buf_pool::alloc_buf(int N)
{
    //1 找到最接近N的一个刻度链表,返回一个io_buf
    int index;
    if(N<=m4k) index = m4k;
    else if(N<=m16k) index = m16k;
    else if(N<=m64k) index = m64k;
    else if(N<=m128k) index = m128k;
    else if(N<=m1M) index = m1M;
    else if(N<=m4M) index = m4M;
    else if(N<=m8M) index = m8M;
    else return NULL;

    //2 如果该index已经没有了,则需要额外的申请内存
    pthread_mutex_lock(&_mutex);
    if(_pool[index]==NULL)
    {   //index链表为空,需要新申请index大小的io_buf
        if(_total_mem+index/1024 >=MEM_LIMIT)
        {
            fprintf(stderr, "memory overflow\n");
            exit(1);
        }

        io_buf *new_buf = new io_buf(index);
        if(new_buf==NULL)
        {
            fprintf(stderr, "no io_buf error\n");
            exit(1);
        }

        _total_mem += index/1024;
        pthread_mutex_unlock(&_mutex);
        return new_buf;
    }
    
    //3 如果改index有剩余节点,从pool中拆除一块内存返回
    io_buf *target = _pool[index];
    _pool[index] = target->next;
    pthread_mutex_unlock(&_mutex);
    target->next = NULL;
    return target;
}

        void buf_pool::revert():将一个已经使用玩的io_buf重置放回POOL中

//重置io_buf放回pool
void buf_pool::revert(io_buf* buffer)
{
    //将buffer放回pool中
    int index = buffer->capacity;
    buffer->length = 0;
    buffer->head = 0;

    pthread_mutex_lock(&_mutex);
    assert(_pool.find(index)!=_pool.end());  //一定能找到key=index
    //将buffer设置为对应的buf链表开始节点
    buffer->next = _pool[index];
    _pool[index] = buffer;
    pthread_mutex_unlock(&_mutex);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值