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);
}

 

posted @ 2012-05-12 21:21  sniperHW  阅读(4171)  评论(0编辑  收藏  举报