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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM