• C语言重写网络发送/接收封包


    本文贴出用C语言重写的网络封包,主体设计思路前文已经介绍过,就是尽可能的共享缓存,减少不必要的内存拷贝.

    其次,封包主要是为了适合网络游戏等有固定模式的,面向字节流的协议,所以并不适合用于http类协议的处理.

    最后,代码没有做优化,内存的分配都是经由calloc,后面会用内存池代替。

    项目地址:https://github.com/sniperHW/KendyNet/tree/master/IOCP

    rpacket从网络中接收到的数据封包:

    #ifndef _RPACKET_H
    #define _RPACKET_H
    
    #include "buffer.h"
    
    typedef struct rpacket
    {
        unsigned long cmd;
        unsigned long len;     //包长
        unsigned long rpos;    //读下标
        unsigned long data_remain;
        unsigned long binbufpos;
        unsigned long begin_pos;
        buffer_t binbuf;       //用于存放跨越buffer_t边界数据的buffer_t
        buffer_t buf;          //存放此数据包内容的buffer_t链表
        buffer_t readbuf;      //当前rpos所在的buffer_t
    }*rpacket_t;
    
    struct wpacket;
    
    rpacket_t rpacket_create(buffer_t,unsigned long pos);
    rpacket_t rpacket_create_by_wpacket(struct wpacket*);//通过wpacket构造
    void      rpacket_destroy(rpacket_t*);
    
    //数据读取接口
    unsigned long  rpacket_len(rpacket_t);
    unsigned long  rpacket_read_cmd(rpacket_t);
    unsigned long  rpacket_data_remain(rpacket_t);
    unsigned char  rpacket_read_char(rpacket_t);
    unsigned short rpacket_read_short(rpacket_t);
    unsigned long  rpacket_read_long(rpacket_t);
    double         rpacket_read_double(rpacket_t);
    const char*    rpacket_read_string(rpacket_t);
    const void*    rpacket_read_binary(rpacket_t,unsigned long *len);
    
    #endif
    #include "rpacket.h"
    #include "wpacket.h"
    #include <stdlib.h>
    #include <string.h>
    
    rpacket_t rpacket_create(buffer_t b,unsigned long pos/*数据在b中的起始下标*/)
    {
        rpacket_t r = calloc(1,sizeof(*r));
        r->binbuf = 0;
        r->binbufpos = 0;
        r->buf = buffer_acquire(0,b);
        r->readbuf = buffer_acquire(0,b);
        r->len = *(unsigned long*)(&(b->buf[pos]));
        r->data_remain = r->len;
        r->rpos = pos + sizeof(r->len);
        r->begin_pos = pos;
        return r;
    }
    
    rpacket_t rpacket_create_by_wpacket(struct wpacket *w)
    {
        rpacket_t r = calloc(1,sizeof(*r));
        r->binbuf = 0;
        r->binbufpos = 0;
        r->buf = buffer_acquire(0,w->buf);
        r->readbuf = buffer_acquire(0,w->buf);
        //这里的len只记录构造时wpacket的len,之后wpacket的写入不会影响到rpacket的len
        r->len = *(unsigned long*)(&(w->buf->buf[w->begin_pos]));
        r->data_remain = r->len;
        r->rpos = 0 + sizeof(r->len);
        r->begin_pos = w->begin_pos;
        return r;
    }
    
    void      rpacket_destroy(rpacket_t *r)
    {
        //释放所有对buffer_t的引用
        buffer_release(&(*r)->buf);
        buffer_release(&(*r)->readbuf);
        buffer_release(&(*r)->binbuf);
    }
    
    unsigned long  rpacket_read_cmd(rpacket_t r)
    {
        return r->cmd;
    }
    
    unsigned long  rpacket_len(rpacket_t r)
    {
        return r->len;
    }
    
    unsigned long  rpacket_data_remain(rpacket_t r)
    {
        return r->data_remain;
    }
    
    static int rpacket_read(rpacket_t r,char *out,unsigned long size)
    {
        buffer_t _next = 0;
        if(r->data_remain < size)
            return -1;
        while(size>0)
        {
            unsigned long copy_size = r->readbuf->size - r->rpos;
            copy_size = copy_size >= size ? size:copy_size;
            memcpy(out,r->readbuf->buf + r->rpos,copy_size);
            size -= copy_size;
            r->rpos += copy_size;
            r->data_remain -= copy_size;
            out += copy_size;
            if(r->rpos >= r->readbuf->size && r->data_remain)
            {
                //当前buffer数据已经被读完,切换到下一个buffer
                r->rpos = 0;
                r->readbuf = buffer_acquire(r->readbuf,r->readbuf->next);
            }
        }
        return 0;
    }
    
    unsigned char  rpacket_read_char(rpacket_t r)
    {
        unsigned char value = 0;
        rpacket_read(r,(char*)&value,sizeof(value));
        return value;
    }
    
    unsigned short rpacket_read_short(rpacket_t r)
    {
        unsigned short value = 0;
        rpacket_read(r,(char*)&value,sizeof(value));
        return value;
    }
    
    unsigned long  rpacket_read_long(rpacket_t r)
    {
        unsigned long value = 0;
        rpacket_read(r,(char*)&value,sizeof(value));
        return value;
    }
    
    double   rpacket_read_double(rpacket_t r)
    {
        double value = 0;
        rpacket_read(r,(char*)&value,sizeof(value));
        return value;
    }
    
    const char* rpacket_read_string(rpacket_t r)
    {
        unsigned long len = 0;
        return (const char *)rpacket_read_binary(r,&len);
    }
    
    const void* rpacket_read_binary(rpacket_t r,unsigned long *len)
    {
        void *addr = 0;
        unsigned long size = rpacket_read_long(r);
        *len = size;
        if(r->data_remain < size)
            return addr;
        if(r->buf->size - r->rpos >= size)
        {
            addr = &r->buf[r->rpos];
            r->rpos += size;
            r->data_remain -= size;
            if(r->rpos >= r->readbuf->size && r->data_remain)
            {
                //当前buffer数据已经被读完,切换到下一个buffer
                r->rpos = 0;
                r->readbuf = buffer_acquire(r->readbuf,r->readbuf->next);
            }
        }
        else
        {
            //数据跨越了buffer边界,创建binbuf,将数据拷贝到binbuf中
            if(!r->binbuf)
            {
                r->binbufpos = 0;
                r->binbuf = buffer_create_and_acquire(0,r->len);
            }
            addr = r->binbuf->buf + r->binbufpos;
            while(size)
            {
                unsigned long copy_size = r->readbuf->size - r->rpos;
                copy_size = copy_size >= size ? size:copy_size;
                memcpy(r->binbuf->buf + r->binbufpos,r->readbuf->buf + r->rpos,copy_size);
                size -= copy_size;
                r->rpos += copy_size;
                r->data_remain -= copy_size;
                r->binbufpos += copy_size;        
                if(r->rpos >= r->readbuf->size && r->data_remain)
                {
                    //当前buffer数据已经被读完,切换到下一个buffer
                    r->rpos = 0;
                    r->readbuf = buffer_acquire(r->readbuf,r->readbuf->next);
                }
            }
    
        }
        return addr;
    }

    wpacket发送数据封包:

    #ifndef _WPACKET_H
    #define _WPACKET_H
    #include "buffer.h"
    typedef struct wpacket
    {
        unsigned long *len;
        buffer_t buf;
        buffer_t writebuf;
        unsigned long wpos;
        unsigned char factor;
        unsigned long begin_pos;
    }*wpacket_t;
    struct rpacket;
    
    
    typedef struct
    {
        buffer_t buf;
        unsigned long wpos;
    }write_pos;
    
    wpacket_t wpacket_create(unsigned long size);
    wpacket_t wpacket_create_by_rpacket(struct rpacket*);//通过rpacket构造
    void wpacket_destroy(wpacket_t*);
    
    write_pos wpacket_get_writepos(wpacket_t);
    
    void wpacket_write_char(wpacket_t,unsigned char);
    void wpacket_write_short(wpacket_t,unsigned short);
    void wpacket_write_long(wpacket_t,unsigned long);
    void wpacket_write_double(wpacket_t,double);
    
    void wpacket_rewrite_char(write_pos*,unsigned char);
    void wpacket_rewrite_short(write_pos*,unsigned short);
    void wpacket_rewrite_long(write_pos*,unsigned long);
    void wpacket_rewrite_double(write_pos*,double);
    
    //不提供对非定长数据的rewrite
    void wpacket_write_string(wpacket_t,const char*);
    void wpacket_write_binary(wpacket_t,const void*,unsigned long);
    #endif
    #include "wpacket.h"
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>
    #include "rpacket.h"
    
    static int is_pow_of_2(unsigned long size)
    {
        return !(size&(size-1));
    }
    
    static unsigned char GetK(unsigned long size)
    {
        unsigned char k = 0;
        if(!is_pow_of_2(size))
        {
            size = (size << 1);
        }
        //除最高为1位以外,其它位全部清0
        while(size > 1)
        {
            k++;
            size = size >> 1;
        }
        return k;
    }
    
    wpacket_t wpacket_create(unsigned long size)
    {
        unsigned char k = GetK(size);
        wpacket_t w;
        size = 1 << k;
        w = calloc(1,sizeof(*w));
        w->factor = k;
        w->wpos = sizeof(w->len);
        w->buf = buffer_create_and_acquire(0,size);
        w->writebuf = buffer_acquire(0,w->buf);
        w->len = (unsigned long*)w->buf->buf;
        *(w->len) = 0;
        w->buf->size = sizeof(w->len);
        w->begin_pos = 0;
        return w;
    }
    
    wpacket_t wpacket_create_by_rpacket(struct rpacket *r)
    {
        wpacket_t w = calloc(1,sizeof(*w));
        w->factor = 0;
        w->writebuf = 0;
        w->begin_pos = r->begin_pos;
        w->buf = buffer_acquire(0,r->buf);
        w->len = (unsigned long*)(r->buf->buf + r->begin_pos);
        w->wpos = 0;
        return w;
    }
    
    write_pos wpacket_get_writepos(wpacket_t w)
    {
        write_pos wp = {w->writebuf,w->wpos};
        return wp;
    }
    
    void wpacket_destroy(wpacket_t *w)
    {
        buffer_release(&(*w)->buf);
        buffer_release(&(*w)->writebuf);
        free(*w);
        *w = 0;
    }
    
    static void wpacket_expand(wpacket_t w)
    {
        unsigned long size;
        w->factor <<= 1;
        size = 1 << w->factor;
        w->writebuf->next = buffer_create_and_acquire(0,size);
        w->writebuf = buffer_acquire(w->writebuf,w->writebuf->next); 
        w->wpos = 0;
    }
    
    
    static void wpacket_copy(wpacket_t w,buffer_t buf)
    {
        char *ptr = buf->buf;
        buffer_t tmp_buf = w->buf;
        unsigned long copy_size;
        while(tmp_buf)
        {
            copy_size = tmp_buf->size - w->wpos;
            memcpy(ptr,tmp_buf->buf,copy_size);
            ptr += copy_size;
            w->wpos = 0;
            tmp_buf = tmp_buf->next;
        }
    }
    
    static void wpacket_write(wpacket_t w,char *addr,unsigned long size)
    {
        char *ptr = addr;
        unsigned long copy_size;
        buffer_t tmp;
        unsigned char k;
        if(!w->writebuf)
        {
            /*wpacket是由rpacket构造的,这里执行写时拷贝,
            * 执行完后wpacket和构造时传入的rpacket不再共享buffer
            */
            k = GetK(*w->len);
            w->factor = k;
            tmp = buffer_create_and_acquire(0,1 << k);
            wpacket_copy(w,tmp);
            w->begin_pos = 0;
            w->len = (unsigned long*)tmp->buf;
            w->wpos = sizeof(*w->len);
            w->buf = buffer_acquire(w->buf,tmp);
            w->writebuf = buffer_acquire(w->writebuf,w->buf);
        }
        while(size)
        {
            copy_size = w->buf->capacity - w->wpos;
            if(copy_size == 0)
            {
                wpacket_expand(w);//空间不足,扩展
                copy_size = w->buf->capacity - w->wpos;
            }
            copy_size = copy_size > size ? size:copy_size;
            memcpy(w->writebuf->buf + w->wpos,ptr,copy_size);
            w->writebuf->size += copy_size;
            (*w->len) += copy_size;
            w->wpos += copy_size;
            ptr += copy_size;
            size -= copy_size;
        }
    }
    
    
    void wpacket_write_char(wpacket_t w,unsigned char value)
    {
        wpacket_write(w,(char*)&value,sizeof(value));
    }
    
    void wpacket_write_short(wpacket_t w,unsigned short value)
    {
        wpacket_write(w,(char*)&value,sizeof(value));
    }
    
    void wpacket_write_long(wpacket_t w,unsigned long value)
    {
        wpacket_write(w,(char*)&value,sizeof(value));
    }
    
    void wpacket_write_double(wpacket_t w ,double value)
    {
        wpacket_write(w,(char*)&value,sizeof(value));
    }
    
    static void wpacket_rewrite(write_pos *wp,char *addr,unsigned long size)
    {
        char *ptr = addr;
        unsigned long copy_size;
        unsigned long pos = wp->wpos;
        while(size)
        {
            copy_size = wp->buf->capacity - pos;
            copy_size = copy_size > size ? size:copy_size;
            memcpy(wp->buf->buf + pos,ptr,copy_size);
            ptr += copy_size;
            size -= copy_size;
            pos += copy_size;
            if(size && pos >= wp->buf->capacity)
            {
                assert(wp->buf->next);
                wp->buf = wp->buf->next;
                pos = 0;
            }
    
        }
    }
    
    void wpacket_rewrite_char(write_pos *wp,unsigned char value)
    {
        wpacket_rewrite(wp,&value,sizeof(value));
    }
    
    void wpacket_rewrite_short(write_pos *wp,unsigned short value)
    {
        wpacket_rewrite(wp,(char*)&value,sizeof(value));
    }
    
    void wpacket_rewrite_long(write_pos *wp,unsigned long value)
    {
        wpacket_rewrite(wp,(char*)&value,sizeof(value));
    }
    
    void wpacket_rewrite_double(write_pos *wp,double value)
    {
        wpacket_rewrite(wp,(char*)&value,sizeof(value));
    }
    
    void wpacket_write_string(wpacket_t w ,const char *value)
    {
        wpacket_write_binary(w,value,strlen(value)+1);
    }
    
    void wpacket_write_binary(wpacket_t w,const void *value,unsigned long size)
    {
        assert(value);
        wpacket_write_long(w,size);
        wpacket_write(w,(char*)value,size);
    }

    简单的测试代码:

    void test1()
    {
        wpacket_t w = wpacket_create(12);
        rpacket_t r,r1;
        wpacket_t w1 = 0;
        const char *str;
        wpacket_write_string(w,"hello kenny");
        r = rpacket_create_by_wpacket(w);
        wpacket_destroy(&w);
        str = rpacket_read_string(r);
        printf("str=%s\n",str);
        w1 = wpacket_create_by_rpacket(r);
        r1 = rpacket_create_by_wpacket(w1);
        str = rpacket_read_string(r1);
        printf("str=%s\n",str);
        rpacket_destroy(&r);
        rpacket_destroy(&r1);
        wpacket_destroy(&w1);
    }
    
    void test2()
    {
        wpacket_t w = wpacket_create(12);
        rpacket_t r;
        write_pos wp;
        wpacket_write_long(w,1);
        wp = wpacket_get_writepos(w);
        wpacket_write_short(w,2);
        wpacket_write_string(w,"hello kenny");
        wpacket_rewrite_short(&wp,4);
        r = rpacket_create_by_wpacket(w);
        printf("%u\n",rpacket_read_long(r));
        printf("%u\n",rpacket_read_short(r));
        printf("%s\n",rpacket_read_string(r));
        rpacket_destroy(&r);
        wpacket_destroy(&w);
    }
  • 相关阅读:
    c++---------------------------->>>>>>>>>>>>>>>>>>遍历文件工具
    图像分割------>>>>>>性能提升30%以上!产业SOTA的实时实例分割算法SOLOv2,更快更强!
    不用绿幕也能实时抠图,商汤等提出只需单张图像、单个模型的新方法MODNet
    目标检测框回归问题
    NeurIPS 2020 | 微软亚洲研究院论文摘录之目标检测篇
    动态规划算法
    FCOS环境搭建配置
    conda--------------------------------->虚拟环境创建
    W: Failed to fetch http://ppa.launchpad.ne
    shell-code-5-函数
  • 原文地址:https://www.cnblogs.com/sniperHW/p/2497518.html
Copyright © 2020-2023  润新知